C++的继承机制允许开发者基于已有的类创建新的类,被继承的类称为基类,新创建的类称为派生类。派生类会自动拥有基类的非私有成员,还可以在此基础上添加新的成员或修改继承来的成员行为,大幅减少重复代码的编写。

C++继承的基本语法
定义派生类的基本语法如下,继承方式可以是public、protected或private,最常用的是public继承:
// 基类定义
class Base {
public:
int public_var;
void public_func() {
// 基类公共方法逻辑
}
protected:
int protected_var;
private:
int private_var;
};
// 派生类定义,public继承Base
class Derived : public Base {
public:
// 派生类新增的公共成员
void derived_func() {
public_var = 10; // 可以访问基类的公共成员
protected_var = 20; // 可以访问基类的保护成员
// private_var = 30; 错误,无法访问基类的私有成员
}
};
不同继承方式的访问权限
继承方式会影响基类成员在派生类中的访问权限,具体规则如下表所示:
| 基类成员权限 | public继承后权限 | protected继承后权限 | private继承后权限 |
|---|---|---|---|
| public | public | protected | private |
| protected | protected | protected | private |
| private | 不可访问 | 不可访问 | 不可访问 |
派生类对基类成员的调用与重写
派生类可以直接调用基类的公共和保护方法,如果需要修改基类方法的实现,可以在派生类中重写该方法,重写时函数签名需要和基类保持一致:
#include <iostream>
using namespace std;
// 基类
class Animal {
public:
void speak() {
cout << "动物发出声音" << endl;
}
};
// 派生类
class Dog : public Animal {
public:
// 重写基类的speak方法
void speak() {
cout << "狗汪汪叫" << endl;
}
// 调用基类的speak方法
void call_base_speak() {
Animal::speak();
}
};
int main() {
Dog dog;
dog.speak(); // 输出:狗汪汪叫
dog.call_base_speak(); // 输出:动物发出声音
return 0;
}
派生类的构造与析构顺序
创建派生类对象时,会先调用基类的构造函数,再调用派生类的构造函数;销毁对象时顺序相反,先调用派生类的析构函数,再调用基类的析构函数:
#include <iostream>
using namespace std;
class Base {
public:
Base() {
cout << "基类构造函数执行" << endl;
}
~Base() {
cout << "基类析构函数执行" << endl;
}
};
class Derived : public Base {
public:
Derived() {
cout << "派生类构造函数执行" << endl;
}
~Derived() {
cout << "派生类析构函数执行" << endl;
}
};
int main() {
Derived d;
// 输出顺序:
// 基类构造函数执行
// 派生类构造函数执行
// 派生类析构函数执行
// 基类析构函数执行
return 0;
}
继承的典型使用场景
继承适合用在存在明显上下级关系的类设计中,比如上面的动物和狗的关系,或者图形基类衍生出圆形、矩形等派生类。使用继承时需要注意避免过深的继承层级,否则会导致代码可读性和维护性下降,如果只需要复用功能而不需要体现层级关系,优先考虑组合而非继承。
注意事项
- 基类的私有成员无论哪种继承方式都无法被派生类直接访问
- 如果基类没有默认构造函数,派生类需要在初始化列表中显式调用基类的有参构造函数
- 重写基类方法时如果希望基类指针指向派生类对象时调用派生类的方法,需要将基类方法声明为虚函数