类与对象

类的介绍

类是用户定义的数据类型,封装数据和函数。它们是 C++ 面向对象编程的基础。

简单类示例

#include <iostream>
#include <string>
using namespace std;

class Student {
private:
    string name;
    int age;
    double gpa;

public:
    // Constructor
    Student(const string& n, int a, double g) {
        name = n;
        age = a;
        gpa = g;
    }
    
    // Getter methods
    string getName() const { return name; }
    int getAge() const { return age; }
    double getGPA() const { return gpa; }
    
    // Method to display information
    void displayInfo() const {
        cout << "Name: " << name << ", Age: " << age << ", GPA: " << gpa << endl;
    }
};

int main() {
    Student student1("Alice", 20, 3.8);
    student1.displayInfo();
    
    return 0;
}

封装

将数据和方法绑定在一起,隐藏内部细节

抽象

为复杂功能提供简化的接口

继承

基于现有类创建新类

多态

使用一个接口处理不同的底层形式

基本类定义

以下是如何定义一个简单的类:

简单类示例

#include <iostream>
#include <string>
using namespace std;

class Student {
private:  // Private members (data hiding)
    string name;
    int age;
    double gpa;

public:   // Public members (interface)
    // Constructor
    Student(const string& n, int a, double g) {
        name = n;
        age = a;
        gpa = g;
    }
    
    // Getter methods
    string getName() const {
        return name;
    }
    
    int getAge() const {
        return age;
    }
    
    double getGPA() const {
        return gpa;
    }
    
    // Setter methods
    void setGPA(double newGPA) {
        if (newGPA >= 0.0 && newGPA <= 4.0) {
            gpa = newGPA;
        }
    }
    
    // Method to display information
    void displayInfo() const {
        cout << "Name: " << name << endl;
        cout << "Age: " << age << endl;
        cout << "GPA: " << gpa << endl;
    }
};

int main() {
    // Create objects
    Student student1("Alice", 20, 3.8);
    Student student2("Bob", 19, 3.5);
    
    // Use methods
    student1.displayInfo();
    cout << "---" << endl;
    student2.displayInfo();
    
    // Modify using setter
    student1.setGPA(3.9);
    cout << "Updated GPA: " << student1.getGPA() << endl;
    
    return 0;
}

构造函数和析构函数

构造函数初始化对象,而析构函数清理资源:

构造函数和析构函数

#include <iostream>
#include <string>
using namespace std;

class Rectangle {
private:
    double width;
    double height;

public:
    // Default constructor
    Rectangle() {
        width = 0.0;
        height = 0.0;
        cout << "Default constructor called" << endl;
    }
    
    // Parameterized constructor
    Rectangle(double w, double h) {
        width = w;
        height = h;
        cout << "Parameterized constructor called" << endl;
    }
    
    // Copy constructor
    Rectangle(const Rectangle& other) {
        width = other.width;
        height = other.height;
        cout << "Copy constructor called" << endl;
    }
    
    // Destructor
    ~Rectangle() {
        cout << "Destructor called for rectangle " 
             << width << "x" << height << endl;
    }
    
    // Methods
    double getArea() const {
        return width * height;
    }
    
    double getPerimeter() const {
        return 2 * (width + height);
    }
    
    void display() const {
        cout << "Rectangle: " << width << " x " << height 
             << " (Area: " << getArea() << ")" << endl;
    }
};

int main() {
    cout << "Creating rectangles:" << endl;
    
    Rectangle rect1;                    // Default constructor
    Rectangle rect2(5.0, 3.0);         // Parameterized constructor
    Rectangle rect3 = rect2;            // Copy constructor
    
    cout << "\nRectangle information:" << endl;
    rect1.display();
    rect2.display();
    rect3.display();
    
    cout << "\nExiting main (destructors will be called):" << endl;
    return 0;
}

访问修饰符

C++ 为类成员提供三种访问级别:

访问级别 同一类 派生类 类外部
private
protected
public

访问修饰符示例

#include <iostream>
using namespace std;

class BankAccount {
private:
    double balance;        // Only accessible within the class
    string accountNumber;  // Hidden from outside access

protected:
    int accountType;       // Accessible in derived classes

public:
    string ownerName;      // Accessible everywhere
    
    // Constructor
    BankAccount(const string& owner, const string& accNum, double initialBalance) {
        ownerName = owner;
        accountNumber = accNum;
        balance = initialBalance;
        accountType = 1;  // Default type
    }
    
    // Public methods to access private data
    double getBalance() const {
        return balance;
    }
    
    void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
            cout << "Deposited $" << amount << endl;
        }
    }
    
    bool withdraw(double amount) {
        if (amount > 0 && amount <= balance) {
            balance -= amount;
            cout << "Withdrew $" << amount << endl;
            return true;
        }
        cout << "Insufficient funds or invalid amount" << endl;
        return false;
    }
    
    void displayInfo() const {
        cout << "Owner: " << ownerName << endl;
        cout << "Balance: $" << balance << endl;
        // cout << "Account: " << accountNumber << endl;  // Can access private here
    }
};

int main() {
    BankAccount account("John Doe", "123456789", 1000.0);
    
    // Can access public members
    cout << "Account holder: " << account.ownerName << endl;
    
    // Can use public methods
    account.deposit(500.0);
    account.withdraw(200.0);
    account.displayInfo();
    
    // Cannot access private members directly
    // cout << account.balance;        // Error!
    // cout << account.accountNumber;  // Error!
    
    return 0;
}

静态成员

静态成员属于类而不是单个对象:

静态成员示例

#include <iostream>
using namespace std;

class Counter {
private:
    int value;
    static int totalObjects;  // Static data member

public:
    // Constructor
    Counter(int val = 0) : value(val) {
        totalObjects++;  // Increment when object is created
    }
    
    // Destructor
    ~Counter() {
        totalObjects--;  // Decrement when object is destroyed
    }
    
    // Regular member function
    int getValue() const {
        return value;
    }
    
    void setValue(int val) {
        value = val;
    }
    
    // Static member function
    static int getTotalObjects() {
        return totalObjects;  // Can only access static members
        // return value;      // Error! Cannot access non-static members
    }
    
    // Static member function to display count
    static void displayCount() {
        cout << "Total Counter objects: " << totalObjects << endl;
    }
};

// Definition of static member (required outside class)
int Counter::totalObjects = 0;

int main() {
    cout << "Initial count: ";
    Counter::displayCount();  // Call static function using class name
    
    Counter c1(10);
    Counter c2(20);
    
    cout << "After creating 2 objects: ";
    Counter::displayCount();
    
    {
        Counter c3(30);
        cout << "After creating 3rd object: ";
        Counter::displayCount();
    }  // c3 goes out of scope and is destroyed
    
    cout << "After c3 is destroyed: ";
    Counter::displayCount();
    
    // Can also call static function through object
    cout << "Total objects (via object): " << c1.getTotalObjects() << endl;
    
    return 0;
}

友元函数

友元函数可以访问类的私有和保护成员:

友元函数示例

#include <iostream>
#include <cmath>
using namespace std;

class Point {
private:
    double x, y;

public:
    Point(double xVal = 0, double yVal = 0) : x(xVal), y(yVal) {}
    
    void display() const {
        cout << "(" << x << ", " << y << ")";
    }
    
    // Declare friend function
    friend double distance(const Point& p1, const Point& p2);
    friend Point midpoint(const Point& p1, const Point& p2);
    
    // Friend class declaration (if needed)
    friend class Line;
};

// Friend function definition
double distance(const Point& p1, const Point& p2) {
    // Can access private members x and y directly
    double dx = p1.x - p2.x;
    double dy = p1.y - p2.y;
    return sqrt(dx * dx + dy * dy);
}

Point midpoint(const Point& p1, const Point& p2) {
    // Can access private members directly
    return Point((p1.x + p2.x) / 2, (p1.y + p2.y) / 2);
}

// Example of friend class
class Line {
private:
    Point start, end;

public:
    Line(const Point& s, const Point& e) : start(s), end(e) {}
    
    void displayLine() const {
        cout << "Line from ";
        start.display();
        cout << " to ";
        end.display();
        cout << endl;
        
        // Can access private members of Point because Line is a friend
        cout << "Start coordinates: x=" << start.x << ", y=" << start.y << endl;
        cout << "End coordinates: x=" << end.x << ", y=" << end.y << endl;
    }
};

int main() {
    Point p1(3, 4);
    Point p2(7, 1);
    
    cout << "Point 1: ";
    p1.display();
    cout << endl;
    
    cout << "Point 2: ";
    p2.display();
    cout << endl;
    
    cout << "Distance: " << distance(p1, p2) << endl;
    
    Point mid = midpoint(p1, p2);
    cout << "Midpoint: ";
    mid.display();
    cout << endl;
    
    Line line(p1, p2);
    line.displayLine();
    
    return 0;
}

类的最佳实践

封装原则

保持数据成员私有,提供公共方法进行访问

构造函数初始化

使用初始化列表以获得更好的性能和常量成员

常量正确性

如果方法不修改对象状态,将其标记为 const

RAII 原则

资源获取即初始化 - 在构造函数/析构函数中管理资源

单一职责

每个类应该只有一个改变的理由

有意义的命名

为类、方法和成员使用描述性名称