一、继承与派生的核心概念
继承是 C++ 实现代码复用 和多态的基础:
- 基类(父类):被继承的类,定义了通用的属性和方法。
- 派生类(子类):从基类继承而来的类,可复用基类的成员,也可扩展新的成员或重写基类方法。你可以把继承理解为 "特殊化"------ 派生类是基类的一种特殊形式(例如:学生是人的特殊形式)。
二、继承的基本语法
1. 定义派生类
语法格式:
cpp
运行
class 派生类名 : 继承方式 基类名 {
// 派生类新增的成员(属性/方法)
};
继承方式有三种(核心是控制基类成员在派生类中的访问权限):
| 继承方式 | 基类 public 成员 | 基类 protected 成员 | 基类 private 成员 |
|---|---|---|---|
| public | public | protected | 不可访问 |
| protected | protected | protected | 不可访问 |
| private | private | private | 不可访问 |
| 👉 最常用的是 public 继承,也是符合 "is-a" 逻辑的继承方式。 |
2. 基础示例(public 继承)
cpp
运行
#include <iostream>
#include <string>
using namespace std;
// 基类:人类
class Person {
public:
// 构造函数
Person(string n, int a) : name(n), age(a) {}
// 公有方法
void ShowInfo() {
cout << "姓名:" << name << ",年龄:" << age << endl;
}
// 可被派生类重写的方法
void SayHello() {
cout << "我是一个普通人" << endl;
}
protected:
// 保护成员:派生类可访问,外部不可访问
string name;
private:
// 私有成员:仅基类自身可访问
int age;
};
// 派生类:学生(public继承Person)
class Student : public Person {
public:
// 派生类构造函数:必须先调用基类构造函数初始化基类成员
Student(string n, int a, int id) : Person(n, a), studentId(id) {}
// 新增方法
void ShowStudentInfo() {
// 可访问基类的protected成员name
cout << "姓名:" << name << ",学号:" << studentId << endl;
// age是private,此处访问会报错:error: 'int Person::age' is private
// cout << age << endl;
}
// 重写基类方法(覆盖)
void SayHello() {
cout << "我是学生,姓名:" << name << endl;
}
private:
// 新增私有成员
int studentId;
};
int main() {
// 创建派生类对象
Student stu("张三", 18, 2025001);
// 调用继承自基类的方法
stu.ShowInfo(); // 输出:姓名:张三,年龄:18
// 调用派生类新增方法
stu.ShowStudentInfo(); // 输出:姓名:张三,学号:2025001
// 调用重写后的方法
stu.SayHello(); // 输出:我是学生,姓名:张三
return 0;
}
三、继承中的核心规则
1. 构造函数与析构函数
-
构造顺序 :先调用基类构造函数 → 再调用派生类构造函数。
-
析构顺序 :先调用派生类析构函数 → 再调用基类析构函数。
-
派生类构造函数必须显式 / 隐式初始化基类: cpp
运行
// 显式调用基类构造函数(推荐) Student(string n, int a, int id) : Person(n, a), studentId(id) {} // 隐式调用:如果基类有默认构造函数(无参),可省略 class Person { public: Person() {} // 默认构造函数 }; class Student : public Person { public: Student(int id) : studentId(id) {} // 隐式调用Person() };
2. 方法重写(覆盖)
- 派生类可以重写基类的非 private 方法,但需注意:
- 默认情况下,重写不会形成多态(需结合
virtual关键字,见下文)。 - 重写的方法签名(返回值、参数、const)必须与基类完全一致。
- 默认情况下,重写不会形成多态(需结合
3. 多态(虚函数)
如果希望通过基类指针 / 引用调用派生类的重写方法(动态多态),需将基类方法声明为virtual:
cpp
运行
// 基类:将SayHello声明为虚函数
class Person {
public:
virtual void SayHello() { // 虚函数
cout << "我是一个普通人" << endl;
}
};
// 派生类:重写虚函数
class Student : public Person {
public:
void SayHello() override { // override关键字显式声明重写(C++11+)
cout << "我是学生" << endl;
}
};
int main() {
Person* p = new Student(); // 基类指针指向派生类对象
p->SayHello(); // 输出:我是学生(动态多态)
delete p;
return 0;
}
4. 继承的特殊形式
-
单继承:一个派生类只继承一个基类(上文示例),最常用。
-
多继承 :一个派生类继承多个基类(C++ 特有,需谨慎使用):
cpp
运行
// 基类1 class A { public: void FuncA() { cout << "A" << endl; } }; // 基类2 class B { public: void FuncB() { cout << "B" << endl; } }; // 多继承 class C : public A, public B { public: void FuncC() { cout << "C" << endl; } }; int main() { C c; c.FuncA(); // 输出A c.FuncB(); // 输出B c.FuncC(); // 输出C return 0; }❗ 多继承易引发 "菱形继承" 问题(两个基类继承同一个基类,派生类继承这两个基类),需用
virtual继承解决。
四、继承的典型应用场景
-
代码复用:将多个类的通用属性 / 方法抽离为基类,派生类直接继承,避免重复代码。
-
多态设计 :通过基类指针 / 引用统一管理不同派生类对象,例如:
cpp
运行
// 基类:图形 class Shape { public: virtual double GetArea() = 0; // 纯虚函数(抽象方法) }; // 派生类:圆形 class Circle : public Shape { private: double r; public: Circle(double r) : r(r) {} double GetArea() override { return 3.14 * r * r; } }; // 派生类:矩形 class Rectangle : public Shape { private: double w, h; public: Rectangle(double w, double h) : w(w), h(h) {} double GetArea() override { return w * h; } }; // 统一计算面积 void PrintArea(Shape* s) { cout << "面积:" << s->GetArea() << endl; } int main() { PrintArea(new Circle(5)); // 输出:面积:78.5 PrintArea(new Rectangle(4, 5)); // 输出:面积:20 return 0; } -
分层设计:例如框架中的基类定义核心接口,派生类实现具体业务逻辑。
总结
- 继承核心 :派生类通过
public/protected/private继承基类,复用基类成员并扩展自身功能,构造先基后派、析构先派后基。 - 访问控制:public 继承是最常用的方式,基类 public/protected 成员在派生类中保持原有访问权限,private 成员不可访问。
- 多态关键 :基类方法声明为
virtual,派生类用override重写,可通过基类指针 / 引用实现动态多态,这是继承的核心价值之一。