当前位置: 首页 > news >正文

深入理解C++多态:从概念到实现

目录

前言

一、多态的概念

二、多态的实现条件

三、虚函数与重写

3.1 虚函数

3.2 虚函数重写

四、抽象类

五、多态的原理

5.1 虚函数表(虚表)

5.2 多态调用过程

六、继承中的虚表

6.1 单继承

6.2 多继承

七、常见问题

八、面试题解析

总结


前言

多态是面向对象编程的三大特性之一(封装、继承、多态),也是C++中最为强大的特性之一。它允许我们以统一的方式处理不同类型的对象,极大地提高了代码的灵活性和可扩展性。本文将全面解析C++多态的概念、实现原理以及相关技术细节。


一、多态的概念

多态(Polymorphism)源自希腊语,意为"多种形态"。在编程中,它指的是同一个行为在不同对象上表现出不同的状态。

生活中的例子:
- 买票行为:普通人全价,学生半价,军人优先
- 支付宝红包:不同用户扫码获得不同金额的红包

这些例子都体现了"同一行为,不同表现"的多态思想。

二、多态的实现条件

在C++中,要实现多态需要满足两个基本条件:

1. 必须通过基类的指针或引用调用虚函数
2. 被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写

 

class Person {
public:virtual void BuyTicket() { cout << "买票-全价" << endl; }
};class Student : public Person {
public:virtual void BuyTicket() { cout << "买票-半价" << endl; }
};void Func(Person& p) {p.BuyTicket();  // 多态调用
}


 

三、虚函数与重写

3.1 虚函数

使用`virtual`关键字修饰的成员函数称为虚函数:


 

virtual 返回类型 函数名(参数列表);


 

3.2 虚函数重写

派生类中重写基类虚函数时需要满足"三同"原则:
- 函数名相同
- 参数列表相同
- 返回值类型相同(协变例外)

协变:派生类重写基类虚函数时,返回值类型可以是基类虚函数返回类型的派生类。
 

class A {};
class B : public A {};class Person {
public:virtual A* f() { return new A; }
};class Student : public Person {
public:virtual B* f() { return new B; }  // 协变
};

四、抽象类

包含纯虚函数的类称为抽象类(接口类),不能实例化对象。


 

class Car {
public:virtual void Drive() = 0;  // 纯虚函数
};


 

抽象类强制派生类实现特定接口,体现了接口继承的思想。

五、多态的原理

5.1 虚函数表(虚表)

每个包含虚函数的类都有一个虚表,其中存储了虚函数的地址。对象中包含一个指向虚表的指针(vfptr)。


 

class Base {
public:virtual void Func1() { /*...*/ }virtual void Func2() { /*...*/ }
private:int _b = 1;
};


 

`sizeof(Base)`在32位系统下为8字节(4字节vfptr + 4字节int)。

5.2 多态调用过程

1. 通过对象的vfptr找到虚表
2. 在虚表中查找对应的虚函数
3. 调用该函数

这种运行时确定调用函数的过程称为动态绑定

六、继承中的虚表

6.1 单继承

派生类虚表包含:
1. 基类虚函数(被重写的会被覆盖)
2. 派生类新增的虚函数

6.2 多继承

派生类会有多个虚表(对应每个基类),未重写的虚函数放在第一个基类的虚表中。

七、常见问题

1. inline函数可以是虚函数吗?
   可以,但编译器会忽略inline属性。

2. 静态成员可以是虚函数吗?
   不能,因为没有this指针。

3. 构造函数可以是虚函数吗? 
   不能,因为虚表指针在构造函数中初始化。

4. 析构函数应该是虚函数吗?  
   基类析构函数应该是虚函数,确保正确调用派生类析构函数。

八、面试题解析

8.1 选择题示例

题目:以下程序输出结果是什么?

class A {
public:virtual void func(int val = 1) { cout << "A->" << val << endl; }virtual void test() { func(); }
};class B : public A {
public:void func(int val = 0) { cout << "B->" << val << endl; }
};int main() {B* p = new B;p->test();return 0;
}

答案:B->1  
解析:虽然B重写了func,但默认参数在编译时确定,使用的是基类的默认参数。

8.2 问答题示例

题目:多态的实现原理?  
答案:通过虚函数表和虚表指针实现。每个包含虚函数的类有一个虚表,对象中包含指向虚表的指针。调用虚函数时,通过指针找到虚表,再找到对应的函数地址进行调用。


总结

多态是C++中强大而复杂的特性,理解其底层实现原理对于编写高效、灵活的面向对象程序至关重要。通过本文的讲解,希望读者能够深入理解多态的概念、实现方式以及相关技术细节,在实际开发中灵活运用这一强大特性。

http://www.dtcms.com/a/322754.html

相关文章:

  • AudioLLM
  • 人工智能-python-特征选择-皮尔逊相关系数
  • 第15届蓝桥杯Scratch选拔赛初级及中级(STEMA)2023年12月17日真题
  • Python爬虫实战:构建国际营养数据采集系统
  • 非常简单!从零学习如何免费制作一个lofi视频
  • 【GitHub小娱乐】GitHub个人主页ProFile美化
  • 怎么选择和怎么填写域名解析到 阿里云ECS
  • 【Redis】Redis-plus-plus的安装与使用
  • 【pyqt5】SP_(Standard Pixmap)的标准图标常量及其对应的图标
  • elementui cascader 远程加载请求使用 选择单项等
  • AcWing 4579. 相遇问题
  • 生物多样性智慧化监测平台
  • 麒麟linux服务器搭建ftp服务【经典版】
  • 本地WSL部署接入 whisper + ollama qwen3:14b 总结字幕
  • 量化投资初探:搭建比特币智能交易机器人
  • 当AI成为语言桥梁:Seq2Seq的机器翻译革命
  • [CUDA] CUTLASS | `CuTe DSL` 创新
  • C# 使用iText获取PDF的trailer数据
  • 基于springboot+vue开发的校园食堂评价系统【源码+sql+可运行】【50809】
  • Baumer高防护相机如何通过YoloV8深度学习模型实现输电线路塔电缆检测分割(C#代码UI界面版)
  • 《Resolving tissue complexity by multimodal spatial omics modeling with MISO》
  • Python人工智能matplotlib中markers属性介绍
  • 【高等数学】第八章 向量代数与空间解析几何——第四节 空间直线及其方程
  • ABP VNext + Apache Kafka Exactly-Once 语义:金融级消息一致性实战
  • Linux用户和组管理及Apache服务安装
  • 浅谈 VM 桥接模式:让虚拟机像真实电脑一样接入网络
  • Go语言实战案例:表单提交数据解析
  • CMU-15445(8)——PROJECT#3-Query Execution-Task#1
  • 前端工程化:从构建工具到性能监控的全流程实践
  • DeepSeek智能考试系统智能体