C++ 类与对象

类(class)是 C++ 面向对象编程(OOP) 的核心。简单说,类是一种自定义类型,把"数据"(成员变量)和"操作数据的方法"(成员函数)打包到一起。这一章我们看类的基础:定义、构造析构、访问控制、this 指针、运算符重载。

一、为什么需要类?

在 C 里你写一个"学生",要这么干:

类的封装(encapsulation)把数据和操作绑在一起,且能控制外部访问权限。这让大型程序的复杂度可控

二、定义第一个类

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

// class 定义一个"类"(自定义类型)
class Student {
private:             // 私有:外部不能直接访问(封装)
    string name;
    int age;

public:              // 公有:外部可以访问
    // 成员函数(方法)
    void introduce() {
        cout << "我是 " << name << ", " << age << " 岁" << endl;
    }

    // setter(通过公有方法控制对私有数据的访问)
    void setAge(int a) {
        if (a < 0 || a > 150) {
            cout << "年龄无效!" << endl;
            return;
        }
        age = a;
    }

    void setName(const string& n) {
        name = n;
    }
};

int main() {
    Student s;             // 创建对象(实例化)
    s.setName("Alice");
    s.setAge(20);
    s.introduce();         // 我是 Alice, 20 岁
    // s.age = 999;         // 编译错误:age 是 private
    return 0;
}

几个关键概念:

三、构造函数

构造函数(constructor)是对象创建时自动调用的特殊函数,用于初始化。名字和类名相同,无返回类型:

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

class Student {
private:
    string name;
    int age;

public:
    // 1. 默认构造函数(无参)
    Student() {
        name = "未知";
        age = 0;
        cout << "默认构造" << endl;
    }

    // 2. 带参构造(可以重载)
    Student(const string& n, int a) {
        name = n;
        age = a;
        cout << "带参构造: " << name << endl;
    }

    // 3. 委托构造(C++11):让一个构造函数调另一个
    Student(const string& n) : Student(n, 18) {}

    // 4. 成员初始化列表(推荐,比在 {} 里赋值更高效)
    Student(int a, const string& n) : name(n), age(a) {
        cout << "用初始化列表构造" << endl;
    }

    void show() {
        cout << name << ", " << age << endl;
    }
};

int main() {
    Student s1;                  // 调默认构造
    Student s2("Bob", 20);       // 调带参构造
    Student s3("Carol");         // 调单参构造
    s1.show();    // 未知, 0
    s2.show();    // Bob, 20
    return 0;
}

要点:

四、= default 与 = delete(C++11)

#include <iostream>
using namespace std;

class A {
public:
    A() = default;             // 显式要求默认构造(C++11)
    A(const A&) = delete;      // 禁止拷贝(单例/智能指针常用)
    A& operator=(const A&) = delete;  // 禁止赋值
};

class B {
public:
    B(int x) {}                // 自定义构造后,编译器不再生成默认构造
    // 想要默认构造,需要显式:
    // B() = default;
};

int main() {
    A a1;                       // OK
    // A a2 = a1;               // 编译错误:拷贝构造被 delete
    B b(10);                    // OK
    // B b2;                    // 编译错误:没有默认构造
    return 0;
}

五、析构函数:清理资源

析构函数(destructor)是对象销毁时自动调用的函数,名字是 ~类名,无参数无返回:

#include <iostream>
using namespace std;

class Buffer {
private:
    int* data;
    size_t size;
public:
    // 构造函数:分配资源
    Buffer(size_t n) : size(n) {
        data = new int[n];      // 在堆上分配
        cout << "分配 " << n << " 个 int" << endl;
    }

    // 析构函数:对象销毁时自动调用,清理资源
    ~Buffer() {
        delete[] data;          // 必须释放,否则内存泄漏!
        cout << "释放 " << size << " 个 int" << endl;
    }

    void fill(int v) {
        for (size_t i = 0; i < size; i++) data[i] = v;
    }
};

int main() {
    {
        Buffer buf(10);          // 进入作用域:构造
        buf.fill(42);
        cout << "使用 buf..." << endl;
    }                            // 出作用域:析构(自动调用 ~Buffer)
    cout << "buf 已销毁" << endl;
    return 0;
}

析构的核心用途:释放构造函数申请的资源(堆内存、文件句柄、锁)。这是 C++ 程序员最重要的责任——忘记析构释放 = 内存泄漏

析构调用时机:

六、this 指针

this指向当前对象的指针,在成员函数里隐式可用:

#include <iostream>
using namespace std;

class Box {
private:
    double width, height;
public:
    Box(double w, double h) : width(w), height(h) {}

    // this 是指向当前对象的指针
    double area() {
        return this->width * this->height;   // this->width 等同于 width
    }

    bool isLargerThan(const Box& other) {
        return this->area() > other.area();
    }

    // this 常见用途 1:参数名和成员名冲突时消歧
    void setWidth(double width) {
        this->width = width;     // this->width 是成员,width 是参数
    }

    // this 常见用途 2:链式调用(返回 *this)
    Box& addWidth(double dw) {
        width += dw;
        return *this;            // 返回当前对象的引用
    }
};

int main() {
    Box b(3, 4);
    cout << b.area() << endl;    // 12

    // 链式调用:连续调用返回引用的方法
    b.addWidth(1).addWidth(2);   // width 从 3 -> 4 -> 6
    cout << b.area() << endl;    // 24
    return 0;
}

this 的常见用途:

七、struct vs class

在 C++ 里,structclass 几乎一样,唯一区别是默认访问权限:

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

// struct 和 class 几乎一样,唯一区别:默认访问权限
// struct 默认 public,class 默认 private

struct Point {                  // 默认 public
    int x;
    int y;
    // 不写构造函数,可以"聚合初始化"
};

class BankAccount {             // 默认 private
    double balance;
public:
    BankAccount(double b) : balance(b) {}
    double getBalance() { return balance; }
};

int main() {
    Point p{3, 4};              // OK:struct 聚合初始化
    cout << p.x << ", " << p.y << endl;   // 3, 4

    BankAccount acc(100);
    // acc.balance;             // 编译错误:private
    cout << acc.getBalance() << endl;     // 100
    return 0;
}

八、运算符重载

C++ 独有的特性:可以给自定义类型定义运算符的含义。比如让两个 Vector 相加用 +、让 cout 能打印自定义类:

#include <iostream>
using namespace std;

class Vector2D {
public:
    double x, y;

    Vector2D(double x = 0, double y = 0) : x(x), y(y) {}

    // 重载 + 运算符:成员函数方式
    Vector2D operator+(const Vector2D& rhs) const {
        return Vector2D(x + rhs.x, y + rhs.y);
    }

    // 重载 == 运算符
    bool operator==(const Vector2D& rhs) const {
        return x == rhs.x && y == rhs.y;
    }

    // 重载 << 让 cout 能打印(必须是非成员函数,通常是 friend)
    friend ostream& operator<<(ostream& os, const Vector2D& v);
};

// friend 函数:可以访问类的私有成员
ostream& operator<<(ostream& os, const Vector2D& v) {
    os << "(" << v.x << ", " << v.y << ")";
    return os;
}

int main() {
    Vector2D a(1, 2), b(3, 4);
    Vector2D c = a + b;          // 调用 operator+
    cout << c << endl;           // (4, 6)
    cout << (a == b) << endl;    // 0
    return 0;
}

运算符重载的要点:

九、static 成员

static 成员属于类本身而不是某个对象,所有对象共享一份:

#include <iostream>
using namespace std;

class Counter {
private:
    int id;
    static int total;     // 静态成员:所有对象共享一份

public:
    Counter() {
        total++;
        id = total;
        cout << "创建第 " << id << " 个对象" << endl;
    }

    static int getTotal() {   // 静态方法:不依赖对象,通过类名调用
        return total;
    }
};

// 静态成员必须在类外定义(C++17 才能用 inline 在类内初始化)
int Counter::total = 0;

int main() {
    cout << Counter::getTotal() << endl;   // 0(通过类名调静态方法)
    Counter a, b, c;
    cout << "总数: " << Counter::getTotal() << endl;   // 3
    return 0;
}

小结

这一章你掌握了 C++ 面向对象的基础:类的定义、public/private/protected、构造函数(含初始化列表、= default/delete)、析构函数、this 指针、struct vs class、运算符重载、static 成员。下一篇我们看继承与多态——怎么复用已有的类。

← 上一篇 C++ 引用

下一篇 C++ 继承

✈️💬