C++ 继承与多态完全详解
2026/7/23 3:27:24 网站建设 项目流程

面向对象三大特性:封装、继承、多态

如果说封装让代码更安全,那么继承让代码复用多态让代码可扩展

继承和多态是 C++ 面向对象的重中之重、面试必考、工程必用。很多同学学完只会背概念,分不清重写、重载、隐藏,不懂虚函数原理,不知道动态绑定到底是什么。

本文带你从零吃透:继承体系 + 访问权限 + 构造析构规则 + 多态原理 + 虚函数 + 纯虚函数 + 抽象类,全程配图、流程图、可运行代码,一次性搞定所有难点。

一、什么是继承(核心概念)

1.1 生活理解

继承:子类拥有父类的所有属性和行为,并且可以扩展自己的新功能。

  • 父类(基类):通用、抽象、公共代码

  • 子类(派生类):特有、扩展、个性化代码

1.2 继承的作用

  1. 代码复用:公共代码只写一次,所有子类直接复用

  2. 代码分层:结构清晰,层级明确

  3. 为多态做铺垫:没有继承,就没有多态

1.3 继承语法

class 子类名 : 继承方式 父类名 { // 子类新成员 };

1.4 三种继承方式(面试重点)

C++ 支持三种继承:public / protected / private

继承方式

父类 public

父类 protected

父类 private

使用场景

public 公有继承

public

protected

不可见

日常开发 99% 使用

protected 保护继承

protected

protected

不可见

极少用

private 私有继承

private

private

不可见

几乎不用

核心结论

  • private 成员永远无法被子类继承访问

  • 想让父类成员子类能用、外部不能用→ 用protected

  • 工程开发只记:一律使用 public 继承

二、继承中的构造与析构顺序

2.1 核心规则

构造函数:先父后子

析构函数:先子后父

2.2 执行流程可视化

2.3 验证代码

#include <iostream> using namespace std; class Parent { public: Parent() { cout << "父类构造" << endl; } ~Parent() { cout << "父类析构" << endl; } }; class Child : public Parent { public: Child() { cout << "子类构造" << endl; } ~Child() { cout << "子类析构" << endl; } }; int main() { Child c; return 0; }

输出顺序

父类构造 → 子类构造 → 子类析构 → 父类析构


三、继承中的同名隐藏(踩坑重点)

3.1 什么是隐藏?

子类和父类有同名成员函数/变量

子类函数会隐藏父类同名函数,父类函数在子类中不可见。

3.2 隐藏 vs 重写(提前区分)

  • 隐藏:普通函数,父子同名,不构成多态

  • 重写(覆盖):虚函数,父子同名同参,构成多态


四、多态详解(OOP 灵魂)

4.1 什么是多态?

多态:同一行为,不同表现

通俗理解:父类指针指向子类对象,调用函数时执行子类的方法

4.2 多态的成立条件(面试必考四条)

必须同时满足:

  1. 存在继承关系

  2. 父类有virtual 虚函数

  3. 子类重写(override)虚函数

  4. 父类指针/引用 指向子类对象

4.3 多态执行原理流程图

4.4 多态完整实战代码

#include <iostream> using namespace std; // 父类 class Animal { public: // 虚函数:支持多态 virtual void speak() { cout << "动物在叫" << endl; } }; // 子类1 class Dog : public Animal { public: // 重写虚函数 void speak() override { cout << "汪汪汪" << endl; } }; // 子类2 class Cat : public Animal { public: void speak() override { cout << "喵喵喵" << endl; } }; // 统一接口,实现多态 void doSpeak(Animal &a) { a.speak(); } int main() { Dog d; Cat c; doSpeak(d); doSpeak(c); return 0; }

输出结果

汪汪汪 、 喵喵喵

关键点:同样的speak()接口,不同对象不同行为,这就是多态。


五、重载、重写、隐藏 终极区别(面试高频)

类型

作用域

函数签名

virtual

是否多态

重载 Overload

同类

函数名同,参数不同

不需要

隐藏 Hide

父子类

同名即可

非虚函数

重写 Override

父子类

完全一致(名/参/返回)

必须 virtual


六、虚函数、纯虚函数、抽象类

6.1 普通虚函数

有默认实现,子类可重写也可不重写。

virtual void func() {}

6.2 纯虚函数(重点)

没有实现,强制子类必须重写

virtual void func() = 0;

6.3 抽象类

包含纯虚函数的类就是抽象类。

特性

  • 无法实例化对象

  • 只能被继承

  • 子类必须实现所有纯虚函数,否则子类也是抽象类

6.4 抽象类实战(接口思想)

#include <iostream> using namespace std; // 抽象父类 class Shape { public: // 纯虚函数 virtual void getArea() = 0; }; class Circle : public Shape { public: void getArea() override { cout << "圆形面积" << endl; } }; class Rect : public Shape { public: void getArea() override { cout << "矩形面积" << endl; } }; int main() { Shape *s1 = new Circle(); Shape *s2 = new Rect(); s1->getArea(); s2->getArea(); delete s1; delete s2; return 0; }

七、多态底层原理:虚函数表 vtable

7.1 什么是虚表?

一旦类中出现virtual函数,编译器会自动生成一张虚函数表

每个对象内存中会多出一个虚表指针 vptr,指向本类的虚表。

7.2 多态调用原理

  1. 父类指针指向子类对象

  2. 通过对象的 vptr 找到虚表

  3. 调用虚表中子类重写后的函数地址

这就是动态绑定(运行时确定调用哪个函数)

7.3 静态绑定 vs 动态绑定

  • 普通函数:静态绑定,编译阶段确定调用地址

  • 虚函数:动态绑定,运行时根据对象真实类型确定


八、继承多态经典坑点:虚析构函数

8.1 问题场景

父类指针 delete 子类对象时:如果析构非虚,只会调用父类析构,子类内存泄漏!

8.2 正确写法

class Parent { public: virtual ~Parent() {} // 虚析构 };

工程规范:只要类可能被继承,析构函数一律写 virtual

九、全文总结

1. 继承核心

  • 目的:代码复用、层级抽象

  • 构造:先父后子

  • 析构:先子后父

  • 开发只用public 继承

2. 多态核心

  • 条件:继承 + 虚函数 + 重写 + 父指子对象

  • 本质:动态绑定、虚函数表

  • 价值:接口统一、扩展性极强(开闭原则)

3. 三大函数区别

  • 重载:同域、参数不同

  • 隐藏:父子同名、非虚函数

  • 重写:父子虚函数、完全覆盖 ——唯一多态

4. 工程准则

  • 需要复用 → 继承

  • 需要统一接口、多场景扩展 → 多态 + 虚函数

  • 基类析构必写 virtual

  • 统一规范用 override 显式重写

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询