
在 C++ 面向对象编程中,继承(Inheritance) 是三大特性(封装、继承、多态)之一,它允许我们基于已有的类创建新的类,实现代码复用、建立类的层次结构。本章将全面讲解类的继承机制,从基础概念到实战应用,帮你彻底掌握继承的核心知识点。

继承的核心思想是 “复用已有代码,扩展新功能”。被继承的类称为基类(Base Class) 或父类,通过继承创建的新类称为派生类(Derived Class) 或子类。
生活中充满继承关系,例如:
UML 类图(PlantText UML):
@startuml
class Animal {
+ name: string
+ eat(): void
+ sleep(): void
}
class Dog {
+ bark(): void
}
class Cat {
+ meow(): void
}
Animal <|-- Dog
Animal <|-- Cat
@enduml
派生类定义语法:
class 派生类名 : 继承方式 基类名1, 继承方式 基类名2, ... {
// 派生类成员
};示例代码:
#include <iostream>
#include <string>
using namespace std;
// 基类:动物
class Animal {
protected:
string name; // 动物名称(保护成员,派生类可访问)
public:
// 构造函数
Animal(string n) : name(n) {
cout << "Animal构造函数被调用" << endl;
}
// 成员函数:吃
void eat() {
cout << name << "在吃东西" << endl;
}
// 成员函数:睡
void sleep() {
cout << name << "在睡觉" << endl;
}
};
// 派生类:狗(公有继承Animal)
class Dog : public Animal {
public:
// 派生类构造函数:必须初始化基类
Dog(string n) : Animal(n) {
cout << "Dog构造函数被调用" << endl;
}
// 派生类新增成员:叫
void bark() {
cout << name << "在汪汪叫" << endl; // 访问基类保护成员
}
};
// 派生类:猫(公有继承Animal)
class Cat : public Animal {
public:
Cat(string n) : Animal(n) {
cout << "Cat构造函数被调用" << endl;
}
// 派生类新增成员:喵
void meow() {
cout << name << "在喵喵叫" << endl;
}
};
// 主函数:程序入口
int main() {
// 创建Dog对象
Dog dog("大黄");
dog.eat(); // 调用基类方法
dog.sleep(); // 调用基类方法
dog.bark(); // 调用派生类方法
cout << endl; // 换行分隔
// 创建Cat对象
Cat cat("小白");
cat.eat(); // 调用基类方法
cat.sleep(); // 调用基类方法
cat.meow(); // 调用派生类方法
return 0;
}
派生类的生成包括三个步骤:
派生类生成流程图

继承方式(公有、私有、保护)决定了基类成员在派生类中的访问权限。基类成员有三种访问级别:public(公有)、private(私有)、protected(保护)。
public成员 → 派生类public成员(类内、类外均可访问)protected成员 → 派生类protected成员(类内可访问,类外不可)private成员 → 派生类不可直接访问(需通过基类公有方法访问)示例代码:
class Base {
public:
int pub; // 公有成员
protected:
int pro; // 保护成员
private:
int pri; // 私有成员
};
// 公有继承
class PubDerived : public Base {
public:
void test() {
pub = 1; // 可访问(public→public)
pro = 2; // 可访问(protected→protected)
// pri = 3; // 错误:私有成员不可直接访问
}
};
int main() {
PubDerived d;
d.pub = 10; // 正确:类外可访问public成员
// d.pro = 20; // 错误:类外不可访问protected成员
return 0;
}public/protected成员 → 派生类private成员(仅派生类内可访问)private成员 → 派生类不可直接访问示例代码:
// 私有继承
class PriDerived : private Base {
public:
void test() {
pub = 1; // 可访问(public→private)
pro = 2; // 可访问(protected→private)
// pri = 3; // 错误
}
};
int main() {
PriDerived d;
// d.pub = 10; // 错误:public继承后变为private,类外不可访问
return 0;
}public成员 → 派生类protected成员protected成员 → 派生类protected成员private成员 → 派生类不可直接访问访问控制对比表:
基类成员 | 公有继承 | 私有继承 | 保护继承 |
|---|---|---|---|
public | public | private | protected |
protected | protected | private | protected |
private | 不可访问 | 不可访问 | 不可访问 |
类型兼容规则是指在需要基类对象的地方,可以使用派生类对象替代,包括:
示例代码:
// 基类
class Base {
public:
void print() { cout << "Base::print()" << endl; }
};
// 派生类
class Derived : public Base {
public:
void print() { cout << "Derived::print()" << endl; } // 重定义
};
int main() {
Derived d;
Base b;
// 1. 派生类对象赋值给基类对象
b = d; // 仅复制基类部分成员
b.print(); // 输出:Base::print()
// 2. 派生类地址赋值给基类指针
Base* pb = &d;
pb->print(); // 输出:Base::print()(未用虚函数,静态绑定)
// 3. 派生类对象作为基类引用
Base& rb = d;
rb.print(); // 输出:Base::print()
return 0;
}类型兼容规则示意图

派生类不能继承基类的构造 / 析构函数,需自行定义,但需负责初始化基类成员。
派生类构造函数语法:
派生类名(参数列表) : 基类名(基类参数), 成员变量(参数) {
// 派生类构造逻辑
}构造函数调用顺序:基类构造函数 → 派生类成员构造函数 → 派生类构造函数
示例代码:
class Base {
public:
Base(int x) : x(x) {
cout << "Base构造函数:x=" << x << endl;
}
private:
int x;
};
class Derived : public Base {
public:
// 派生类构造函数必须初始化基类
Derived(int x, int y) : Base(x), y(y) {
cout << "Derived构造函数:y=" << y << endl;
}
private:
int y;
};
int main() {
Derived d(10, 20);
// 输出顺序:
// Base构造函数:x=10
// Derived构造函数:y=20
return 0;
}派生类复制构造函数需显式调用基类复制构造函数:
class Base {
public:
Base(int x) : x(x) {}
// 基类复制构造函数
Base(const Base& other) : x(other.x) {
cout << "Base复制构造函数" << endl;
}
private:
int x;
};
class Derived : public Base {
public:
Derived(int x, int y) : Base(x), y(y) {}
// 派生类复制构造函数:需调用基类复制构造
Derived(const Derived& other) : Base(other), y(other.y) {
cout << "Derived复制构造函数" << endl;
}
private:
int y;
};
int main() {
Derived d1(10, 20);
Derived d2 = d1; // 调用复制构造函数
// 输出:
// Base复制构造函数
// Derived复制构造函数
return 0;
}析构函数调用顺序与构造函数相反:派生类析构函数 → 派生类成员析构函数 → 基类析构函数
示例代码:
class Base {
public:
~Base() {
cout << "Base析构函数" << endl;
}
};
class Derived : public Base {
public:
~Derived() {
cout << "Derived析构函数" << endl;
}
};
int main() {
Derived d;
// 输出顺序:
// Derived析构函数
// Base析构函数
return 0;
}构造 / 析构调用顺序流程图

使用delete关键字禁用特定构造函数(如复制构造):
class NoCopy {
public:
NoCopy() = default; // 默认构造函数
NoCopy(const NoCopy&) = delete; // 禁用复制构造函数
NoCopy& operator=(const NoCopy&) = delete; // 禁用赋值运算符
};
int main() {
NoCopy a;
// NoCopy b = a; // 错误:复制构造函数已删除
return 0;
}当派生类与基类有同名成员时,需通过特殊方式访问基类成员。
使用基类名::成员名访问基类同名成员:
class Base {
public:
void print() { cout << "Base::print()" << endl; }
};
class Derived : public Base {
public:
void print() {
cout << "Derived::print()" << endl;
Base::print(); // 访问基类print()
}
};
int main() {
Derived d;
d.print(); // 调用派生类print()
d.Base::print(); // 显式调用基类print()
return 0;
} 解决菱形继承(多继承中同一基类被多次继承)的二义性问题,使用virtual声明虚基类:
#include<iostream>
using namespace std;
// 虚基类
class A {
public:
int x;
A(int x) : x(x) {
cout << "A的构造函数被调用,x=" << x << endl;
}
};
// 中间派生类声明A为虚基类
class B : virtual public A {
public:
B(int x) : A(x) {
cout << "B的构造函数被调用" << endl;
}
};
class C : virtual public A {
public:
C(int x) : A(x) {
cout << "C的构造函数被调用" << endl;
}
};
// 最终派生类D只继承A一次
class D : public B, public C {
public:
// 虚基类由最终派生类初始化
D(int x) : A(x), B(x+1), C(x+2) {
cout << "D的构造函数被调用" << endl;
}
void print() {
cout << "x=" << x << endl; // 无歧义,仅一个x
}
};
// 主函数,程序入口
int main() {
// 创建D类对象,测试虚基类功能
D d(10);
d.print(); // 输出x的值,验证没有二义性
// 验证x的唯一性
cout << "通过D对象访问x: " << d.x << endl;
cout << "通过B继承路径访问x: " << d.B::x << endl;
cout << "通过C继承路径访问x: " << d.C::x << endl;
return 0;
}
菱形继承问题与虚基类解决方案
@startuml
' 菱形继承问题
class A
class B {
+ x: int // 继承自A
}
class C {
+ x: int // 继承自A(重复)
}
class D {
+ x: int // 二义性:B::x还是C::x?
}
A <|-- B
A <|-- C
B <|-- D
C <|-- D
note right of D: 问题:D中有两个x副本,访问时二义性
@enduml
@startuml
' 虚基类解决方案
class A
class B <<virtual>> {
+ x: int // 虚继承自A
}
class C <<virtual>> {
+ x: int // 虚继承自A
}
class D {
+ x: int // 仅一个x副本(来自A)
}
A <|-- B
A <|-- C
B <|-- D
C <|-- D
note right of D: 解决:虚基类A在D中只保留一个副本
@enduml
虚基类的构造函数由最终派生类负责初始化,中间派生类的虚基类构造函数调用被忽略:
class A {
public:
A(int x) : x(x) {
cout << "A构造函数:x=" << x << endl;
}
int x;
};
class B : virtual public A {
public:
B(int x) : A(x) { // 中间派生类的虚基类构造会被忽略
cout << "B构造函数" << endl;
}
};
class C : virtual public A {
public:
C(int x) : A(x) { // 中间派生类的虚基类构造会被忽略
cout << "C构造函数" << endl;
}
};
class D : public B, public C {
public:
// 最终派生类必须初始化虚基类A
D(int x) : A(x), B(x+1), C(x+2) {
cout << "D构造函数" << endl;
}
};
int main() {
D d(10); // 输出A构造函数:x=10(仅一次)
return 0;
}高斯消去法通过消元(将方程组化为上三角矩阵)和回代(求解未知数)解线性方程组:
设计Matrix类封装矩阵操作,GaussianElimination类继承Matrix实现高斯消去算法:
eliminate()(消元)、backSubstitute()(回代)#include <iostream>
#include <vector>
#include <cmath>
#include <iomanip>
using namespace std;
// 矩阵基类
class Matrix {
protected:
vector<vector<double>> data; // 矩阵数据
int rows; // 行数
int cols; // 列数
public:
// 构造函数:初始化rows×cols矩阵
Matrix(int rows, int cols) : rows(rows), cols(cols) {
data.resize(rows, vector<double>(cols, 0.0));
}
// 设置矩阵元素
void set(int i, int j, double val) {
if (i >= 0 && i < rows && j >= 0 && j < cols) {
data[i][j] = val;
}
}
// 获取矩阵元素
double get(int i, int j) const {
if (i >= 0 && i < rows && j >= 0 && j < cols) {
return data[i][j];
}
return 0.0;
}
// 获取行数
int getRows() const { return rows; }
// 获取列数
int getCols() const { return cols; }
// 打印矩阵
void print() const {
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
cout << setw(8) << fixed << setprecision(2) << data[i][j];
}
cout << endl;
}
}
};
// 高斯消去法类(继承Matrix)
class GaussianElimination : public Matrix {
private:
vector<double> solution; // 解向量
public:
// 构造函数:n元方程组(增广矩阵n×(n+1))
GaussianElimination(int n) : Matrix(n, n + 1), solution(n, 0.0) {}
// 消元过程:化为上三角矩阵
bool eliminate() {
int n = rows;
for (int k = 0; k < n - 1; ++k) { // 第k步消元
// 找主元(最大值)
int maxRow = k;
for (int i = k; i < n; ++i) {
if (fabs(get(i, k)) > fabs(get(maxRow, k))) {
maxRow = i;
}
}
// 交换行
if (maxRow != k) {
swap(data[k], data[maxRow]);
}
// 检查主元是否为0(奇异矩阵)
if (fabs(get(k, k)) < 1e-10) {
return false; // 无解或无穷多解
}
// 消元计算
for (int i = k + 1; i < n; ++i) {
double factor = get(i, k) / get(k, k);
for (int j = k; j <= n; ++j) {
data[i][j] -= factor * data[k][j];
}
}
}
return true;
}
// 回代过程:求解未知数
void backSubstitute() {
int n = rows;
// 最后一行直接求解
solution[n - 1] = get(n - 1, n) / get(n - 1, n - 1);
// 从倒数第二行向上回代
for (int i = n - 2; i >= 0; --i) {
double sum = 0.0;
for (int j = i + 1; j < n; ++j) {
sum += get(i, j) * solution[j];
}
solution[i] = (get(i, n) - sum) / get(i, i);
}
}
// 打印解
void printSolution() const {
cout << "方程组的解:" << endl;
for (int i = 0; i < solution.size(); ++i) {
cout << "x" << i + 1 << " = " << fixed << setprecision(4) << solution[i] << endl;
}
}
};
int main() {
// 解方程组:
// 2x1 + x2 - x3 = 8
// -3x1 - x2 + 2x3 = -11
// -2x1 + x2 + 2x3 = -3
GaussianElimination ge(3); // 3元方程组
// 设置增广矩阵
ge.set(0, 0, 2); ge.set(0, 1, 1); ge.set(0, 2, -1); ge.set(0, 3, 8);
ge.set(1, 0, -3); ge.set(1, 1, -1); ge.set(1, 2, 2); ge.set(1, 3, -11);
ge.set(2, 0, -2); ge.set(2, 1, 1); ge.set(2, 2, 2); ge.set(2, 3, -3);
cout << "原始增广矩阵:" << endl;
ge.print();
if (ge.eliminate()) {
cout << "\n消元后的上三角矩阵:" << endl;
ge.print();
ge.backSubstitute();
ge.printSolution();
} else {
cout << "\n方程组无解或有无穷多解" << endl;
}
return 0;
}运行结果:

分析:程序通过高斯消去法正确求解线性方程组,消元过程将矩阵化为上三角,回代过程依次求解每个未知数,验证了继承的实用性(GaussianElimination复用Matrix的矩阵操作)。
设计银行账户管理系统,支持不同类型账户(储蓄账户、信用卡账户)的存款、取款、查询等操作,通过继承实现代码复用。
Account:封装账户基本属性(账号、余额)和方法(存款、取款、查询)SavingsAccount:新增利率属性和计息方法CreditAccount:新增信用额度和透支利息计算@startuml
class Account {
- accountId: string
- balance: double
+ Account(id: string, balance: double)
+ deposit(amount: double): bool
+ withdraw(amount: double): bool
+ getBalance(): double
+ getAccountId(): string
+ printInfo(): void
}
class SavingsAccount {
- interestRate: double
+ SavingsAccount(id: string, balance: double, rate: double)
+ calculateInterest(): double
+ addInterest(): void
+ printInfo(): void
}
class CreditAccount {
- creditLimit: double
- overdrawRate: double
+ CreditAccount(id: string, balance: double, limit: double, rate: double)
+ withdraw(amount: double): bool
+ calculateOverdrawInterest(): double
+ printInfo(): void
}
Account <|-- SavingsAccount
Account <|-- CreditAccount
@enduml
#include <iostream>
#include <string>
#include <iomanip>
using namespace std;
// 银行账户基类
class Account {
protected:
string accountId; // 账号
double balance; // 余额
public:
// 构造函数
Account(const string& id, double initialBalance)
: accountId(id), balance(initialBalance) {
// 确保初始余额非负
if (balance < 0) {
cout << "警告:初始余额不能为负,已重置为0" << endl;
balance = 0;
}
}
// 析构函数
virtual ~Account() {}
// 存款
bool deposit(double amount) {
if (amount <= 0) {
cout << "存款金额必须为正数!" << endl;
return false;
}
balance += amount;
return true;
}
// 取款(基类默认实现:不允许透支)
virtual bool withdraw(double amount) {
if (amount <= 0) {
cout << "取款金额必须为正数!" << endl;
return false;
}
if (amount > balance) {
cout << "余额不足,取款失败!" << endl;
return false;
}
balance -= amount;
return true;
}
// 获取余额
double getBalance() const {
return balance;
}
// 获取账号
string getAccountId() const {
return accountId;
}
// 打印账户信息(虚函数,允许派生类重写)
virtual void printInfo() const {
cout << "账号:" << accountId << endl;
cout << "当前余额:" << fixed << setprecision(2) << balance << "元" << endl;
}
};
// 储蓄账户(派生类)
class SavingsAccount : public Account {
private:
double interestRate; // 年利率
public:
// 构造函数
SavingsAccount(const string& id, double initialBalance, double rate)
: Account(id, initialBalance), interestRate(rate) {
// 确保利率合法
if (interestRate < 0) {
cout << "警告:利率不能为负,已重置为0" << endl;
interestRate = 0;
}
}
// 计算利息(年利息)
double calculateInterest() const {
return balance * interestRate;
}
// 增加利息到余额
void addInterest() {
double interest = calculateInterest();
deposit(interest); // 复用基类存款方法
cout << "已结算年利息:" << fixed << setprecision(2) << interest << "元" << endl;
}
// 重写打印信息
void printInfo() const override {
Account::printInfo(); // 调用基类方法
cout << "年利率:" << fixed << setprecision(2) << (interestRate * 100) << "%" << endl;
cout << "年利息:" << fixed << setprecision(2) << calculateInterest() << "元" << endl;
}
};
// 信用卡账户(派生类)
class CreditAccount : public Account {
private:
double creditLimit; // 信用额度
double overdrawRate; // 透支利率(月利率)
public:
// 构造函数
CreditAccount(const string& id, double initialBalance, double limit, double rate)
: Account(id, initialBalance), creditLimit(limit), overdrawRate(rate) {
// 确保参数合法
if (creditLimit < 0) {
cout << "警告:信用额度不能为负,已重置为0" << endl;
creditLimit = 0;
}
if (overdrawRate < 0) {
cout << "警告:透支利率不能为负,已重置为0" << endl;
overdrawRate = 0;
}
}
// 重写取款方法(允许透支,但不超过信用额度)
bool withdraw(double amount) override {
if (amount <= 0) {
cout << "取款金额必须为正数!" << endl;
return false;
}
// 可取款上限:余额 + 信用额度
double maxWithdraw = balance + creditLimit;
if (amount > maxWithdraw) {
cout << "超过信用额度,取款失败!最大可取款:"
<< fixed << setprecision(2) << maxWithdraw << "元" << endl;
return false;
}
balance -= amount;
return true;
}
// 计算透支利息(月利息)
double calculateOverdrawInterest() const {
if (balance >= 0) return 0; // 未透支,无利息
return (-balance) * overdrawRate; // 透支金额×月利率
}
// 重写打印信息
void printInfo() const override {
Account::printInfo(); // 调用基类方法
cout << "信用额度:" << fixed << setprecision(2) << creditLimit << "元" << endl;
cout << "透支月利率:" << fixed << setprecision(2) << (overdrawRate * 100) << "%" << endl;
if (balance < 0) {
cout << "当前透支金额:" << fixed << setprecision(2) << (-balance) << "元" << endl;
cout << "月透支利息:" << fixed << setprecision(2) << calculateOverdrawInterest() << "元" << endl;
}
}
};
// 测试函数
void testAccounts() {
// 创建储蓄账户
SavingsAccount sa("SA123456", 10000, 0.0275); // 年利率2.75%
cout << "\n===== 储蓄账户初始信息 =====" << endl;
sa.printInfo();
sa.deposit(5000); // 存款5000
cout << "\n===== 存款5000后 =====" << endl;
sa.printInfo();
sa.withdraw(3000); // 取款3000
cout << "\n===== 取款3000后 =====" << endl;
sa.printInfo();
sa.addInterest(); // 结算利息
cout << "\n===== 结算利息后 =====" << endl;
sa.printInfo();
// 创建信用卡账户
CreditAccount ca("CA654321", 5000, 10000, 0.0005); // 信用额度1万,月透支利率0.05%
cout << "\n===== 信用卡账户初始信息 =====" << endl;
ca.printInfo();
ca.withdraw(8000); // 取款8000(余额5000,可透支)
cout << "\n===== 取款8000后 =====" << endl;
ca.printInfo();
ca.withdraw(7000); // 再取款7000(测试透支上限)
cout << "\n===== 再取款7000后 =====" << endl;
ca.printInfo();
ca.deposit(10000); // 存款10000
cout << "\n===== 存款10000后 =====" << endl;
ca.printInfo();
}
int main() {
cout << "===== 个人银行账户管理系统 =====" << endl;
testAccounts();
return 0;
}运行结果(部分):
===== 个人银行账户管理系统 =====
===== 储蓄账户初始信息 =====
账号:SA123456
当前余额:10000.00元
年利率:2.75%
年利息:275.00元
===== 存款5000后 =====
账号:SA123456
当前余额:15000.00元
年利率:2.75%
年利息:412.50元
...
===== 信用卡账户初始信息 =====
账号:CA654321
当前余额:5000.00元
信用额度:10000.00元
透支月利率:0.05%
===== 取款8000后 =====
账号:CA654321
当前余额:-3000.00元
信用额度:10000.00元
透支月利率:0.05%
当前透支金额:3000.00元
月透支利息:1.50元 分析:程序通过继承实现了不同账户类型的管理,基类Account提供基础功能,派生类通过重写方法(如withdraw、printInfo)实现个性化需求,体现了继承的代码复用和扩展能力。
示例对比:
// 继承示例(is-a)
class Animal { /* ... */ };
class Dog : public Animal { /* 狗是动物 */ };
// 组合示例(has-a)
class Engine { /* 发动机类 */ };
class Car {
private:
Engine engine; // 汽车有发动机
public:
void start() { engine.start(); } // 复用发动机功能
};选择原则:优先组合(低耦合),需多态时用继承。
派生类对象内存包含基类成员和派生类新增成员(简化模型):
class Base {
public:
int a;
protected:
int b;
private:
int c; // 私有成员也在内存中,但派生类不可直接访问
};
class Derived : public Base {
public:
int d;
};派生类内存布局示意图
+-------------------------+ <-- 对象起始地址
| vptr (4 bytes) | // 指向派生类的虚表
+-------------------------+
| Base::base_data (4 bytes)
+-------------------------+
| Derived::derived_data (4 bytes)
+-------------------------+ <-- 对象结束地址Derived类的虚表:
+-------------------------+
| &Derived::vfunc1 | // 覆盖的虚函数
+-------------------------+
| &Base::vfunc2 | // 继承的基类虚函数
+-------------------------+
| &Derived::vfunc3 | // 派生类新增虚函数
+-------------------------+base_data)位于派生类对象起始位置(紧随vptr之后)。
vfunc1)
vfunc2)
vfunc3)
Base* b = new Derived(); // 安全:派生类→基类指针
Derived* d1 = b; // 错误:基类→派生类无隐式转换
Derived* d2 = static_cast<Derived*>(b); // 显式转换(需确保b指向Derived对象,否则危险)风险示例:
Base b;
Derived* d = static_cast<Derived*>(&b); // 危险!b不是Derived对象
d->d = 10; // 访问不存在的成员,导致未定义行为本章重点:
::用于访问基类同名成员通过高斯消去法和银行账户实例,我们掌握了继承在实际开发中的应用,合理使用继承能显著提高代码质量和开发效率。
类的继承是 C++ 面向对象编程的核心技术,掌握它能帮你设计更灵活、可扩展的系统。建议多动手实践本章代码,深入理解继承的细节和最佳实践。如有问题欢迎在评论区交流!
#C++ #面向对象 #类的继承 #编程学习