C++ 类与对象
更新时间:2026-08-25。本文是
languages/cpp/主题入门层第 1 篇。类是 C++ 面向对象的核心——它把数据和操作数据的方法绑在一起。本文讲清封装、继承、多态三大特性,为后面的虚函数机制(专家层)打基础。
本文要回答的问题
- 类(class)和结构体(struct)有什么区别?
- 构造函数、析构函数分别在什么时候被调用?
- 什么是多态?为什么需要
virtual和虚函数?
一、封装:类与对象
1.1 类的定义
cpp
class Circle {
double radius_; // 成员变量(数据)
public:
double area() const { // 成员函数(方法)
return 3.14159 * radius_ * radius_;
}
void setRadius(double r) { radius_ = r; }
};
Circle c; // c 是 Circle 类的一个对象(实例)
c.setRadius(5.0);
double a = c.area();class vs struct:唯一的区别是默认访问权限——class 默认 private,struct 默认 public。除此之外完全等价。
1.2 访问控制
| 关键字 | 谁可以访问 |
|---|---|
public | 任何地方 |
protected | 本类和派生类 |
private | 仅本类(含友元) |
封装的意义:把数据(radius_)设为 private,通过 public 接口(setRadius)访问,可以控制数据的合法性(比如禁止负半径)。
二、构造函数与析构函数
2.1 构造函数:对象诞生时调用
cpp
class Circle {
double radius_;
public:
Circle() : radius_(1.0) {} // 默认构造
Circle(double r) : radius_(r) {} // 带参构造
};
Circle c1; // 默认构造,radius = 1.0
Circle c2(5.0); // 带参构造,radius = 5.0: 后面是初始化列表(member initializer list),比在函数体里赋值更高效(直接初始化,而非先默认构造再赋值)。
2.2 析构函数:对象销毁时调用
cpp
class Circle {
~Circle() { /* 清理资源 */ }
};析构函数在对象离开作用域时自动调用,是 RAII 的基础(见 RAII 与智能指针)。
2.3 拷贝构造与赋值
cpp
Circle c1(5.0);
Circle c2 = c1; // 拷贝构造(用 c1 初始化 c2)
Circle c3;
c3 = c1; // 拷贝赋值C++ 会自动生成默认的拷贝构造/赋值(逐成员拷贝),但涉及指针等资源时需要自定义(或禁用),详见 移动语义。
三、继承:复用与扩展
3.1 基本继承
cpp
class Shape {
protected:
double area_;
public:
double area() const { return area_; }
};
class Circle : public Shape { // Circle 继承 Shape
double radius_;
public:
Circle(double r) : radius_(r) {
area_ = 3.14159 * r * r; // 访问基类的 protected 成员
}
};: public Shape表示公有继承(最常用):基类的public成员在派生类仍是public。- 派生类能用基类的成员,实现代码复用。
3.2 继承的访问变化
| 继承方式 | 基类 public | 基类 protected | 基类 private |
|---|---|---|---|
public | public | protected | 不可访问 |
protected | protected | protected | 不可访问 |
private | private | private | 不可访问 |
四、多态:同一接口,不同行为
4.1 虚函数与重写
cpp
class Shape {
public:
virtual double area() const { return 0; } // 虚函数
};
class Circle : public Shape {
double r_;
public:
Circle(double r) : r_(r) {}
double area() const override { return 3.14159 * r_ * r_; } // 重写
};
class Square : public Shape {
double s_;
public:
Square(double s) : s_(s) {}
double area() const override { return s_ * s_; }
};4.2 多态的核心:通过基类指针调用派生类
cpp
Shape *shapes[] = { new Circle(5.0), new Square(3.0) };
for (auto *s : shapes) {
s->area(); // 运行时决定调用 Circle::area 还是 Square::area
}关键:s 是 Shape* 类型,但 s->area() 调用的是实际对象(Circle 或 Square)的版本——这就是多态。没有 virtual 的话,s->area() 只会调用基类的版本。
4.3 override 与 final
cpp
double area() const override; // 明确表示重写(写错签名会编译报错)
void draw() const final; // 禁止派生类再重写override:编译器检查是否真的重写了基类虚函数,防拼写错误。final:禁止继续重写。
五、this 指针
成员函数里有个隐藏的 this 指针,指向当前对象:
cpp
class Circle {
double r_;
public:
Circle &setR(double r) {
this->r_ = r; // this-> 显式访问成员
return *this; // 返回当前对象,支持链式调用
}
};
Circle c;
c.setR(1).setR(2); // 链式调用六、与本站主线衔接
- 虚函数的开销:多态通过虚表(vtable)实现,有间接跳转开销,详见专家层 虚函数与虚表。
- 对象内存布局:继承、虚函数如何影响对象大小和对齐,见 对象内存布局。
- 构造/析构与性能:初始化列表、拷贝省略与性能,见 移动语义。
一句话总结
类与对象 = 封装(数据私有 + 接口公有)、继承(复用基类)、多态(虚函数让基类指针调用派生类实现)三大特性;virtual + override 是多态的关键,它把"调用哪个函数"从编译期推迟到运行期。
上一篇:C++ 三层学习路径总纲 下一篇:STL 容器与迭代器