news 2026/4/30 17:31:51

C++多态的实现机制深入理解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++多态的实现机制深入理解

在面试过程中C++的多态实现机制经常会被面试官问道。大家清楚多态到底该如何实现吗?下面小编抽空给大家介绍下多态的实现机制。

1. 用virtual关键字申明的函数叫做虚函数,虚函数肯定是类的成员函数。

2. 存在虚函数的类都有一个一维的虚函数表叫做虚表。类的对象有一个指向虚表开始的虚指针。虚表是和类对应的,虚表指针是和对象对应的。

3. 多态性是一个接口多种实现,是面向对象的核心。分为类的多态性和函数的多态性。

4. 多态用虚函数来实现,结合动态绑定。

5. 纯虚函数是虚函数再加上= 0。

6. 抽象类是指包括至少一个纯虚函数的类。

多态的简单介绍

一般来说,多态分为两种,静态多态和动态多态。静态多态也称编译时多态,主要包括模板和重载。而动态多态则是通过类的继承和虚函数来实现,当基类和子类拥有同名同参同返回的方法,且该方法声明为虚方法,当基类对象,指针,引用指向的是派生类的对象的时候,基类对象,指针,引用在调用基类的方法,实际上调用的是派生类方法。这就是动态多态。

静态多态的实现

静态多态靠编译器来实现,简单来说就是编译器对原来的函数名进行修饰,在c语言中,函数无法重载,是因为,c编译器在修饰函数时,只是简单的在函数名前加上下划线"_" 。而c++编译器不同,它根据函数的类型,个数来对函数名进行修饰,这就使得函数可以重载,同理,模板也是可以实现的,针对不同类型的实参来产生对应的特化的函数,通过增加修饰,使得不同的类型参数的函数得以区分。

以下段程序为例

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

#include <iostream>

usingnamespacestd;

template<typenameT1,typenameT2>

intfun(T1 t1, T2 t2){}

intfoofun(){}

intfoofun(int){}

intfoofun(int,float){}

intfoofun(int,float,double){}

intmain(intargc,char*argv[])

{

fun(1, 2);

fun(1, 1.1);

foofun();

foofun(1);

foofun(1, 1.1);

foofun(1, 1.1, 1.11);

return0;

}

经过编译之后:

只选取main函数部分来看:

可以发现,调用的函数名均发生了变化,都加了相应的修饰,使得调用的函数是不一样的,静态多态就是如此。

动态多态的实现

声明一个类时,如果类中有虚方法,则自动在类中增加一个虚函数指针,该指针指向的是一个虚函数表,虚函数表中存着每个虚函数真正对应的函数地址。动态多态采用一种延迟绑定技术,普通的函数调用,在编译期间就已经确定了调用的函数的地址,所以无论怎样调用,总是那个函数,但是拥有虚函数的类,在调用虚函数时,首先去查虚函数表,然后在确定调用的是哪一个函数,所以,调用的函数是在运行时才会确定的。

在声明基类对象时,虚函数表中绑定的就是基类的方法的地址。在声明派生类对象时,虚函数表中绑定的就是派生类的方法。在对象被创建之后(以指针为例),无论是基类指针还是派生类指针指向这个对象,虚函数表是不会改变的。
以下段程序为例:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

#include <iostream>

usingnamespacestd;

classBase

{

public:

virtualvoidfun()

{

cout <<"this is base fun"<< endl;

}

};

classDerived :publicBase

{

public:

voidfun()

{

cout <<"this is Derived fun"<< endl;

}

};

intmain(intargc,char*argv[])

{

Base b1;

Derived d1;

Base *pb = &d1;

Derived *pd = (Derived *)&b1;

b1.fun();

pd->fun();

d1.fun();

pb->fun();

return0;

}

运行结果如下:

从结果可以看出,当一个对象被创建之后,在调用虚函数的时候,无论是派生类指针还是基类指针指向这个对象,调用虚函数的结果是一样的。因为,虚函数表是不变。当然,有可能在多继承中会有多个虚函数表从而导致函数调用时调用不同的虚函数表,这里不做考虑。


版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/30 17:30:23

为 Claude Code 配置 Taotoken 作为其大模型服务提供商

为 Claude Code 配置 Taotoken 作为其大模型服务提供商 1. 准备工作 在开始配置前&#xff0c;请确保已具备以下条件&#xff1a;已注册 Taotoken 账号并获取有效的 API Key&#xff0c;同时拥有可运行的 Claude Code 环境。Taotoken 提供的 API Key 可在控制台的「API 密钥管…

作者头像 李华
网站建设 2026/4/30 17:27:40

如何用coze实现超纯水系统设计计算

目录 方案架构说明 第一部分:Bot System Prompt 第二部分:Workflow 节点设计 节点总览 节点1:参数解析(LLM节点) 节点2:水量平衡计算(Python代码节点) 节点3:水质预测(Python代码节点) 节点4:报告生成(LLM节点) 第三部分:搭建步骤说明 Bot 配置步骤 …

作者头像 李华
网站建设 2026/4/30 17:26:38

XAPK转APK完整指南:3步解决Android应用安装难题

XAPK转APK完整指南&#xff1a;3步解决Android应用安装难题 【免费下载链接】xapk-to-apk A simple standalone python script that converts .xapk file into a normal universal .apk file 项目地址: https://gitcode.com/gh_mirrors/xa/xapk-to-apk 你是否曾经下载过…

作者头像 李华
网站建设 2026/4/30 17:26:35

终极RyzenAdj调优指南:3步解锁锐龙处理器隐藏性能

终极RyzenAdj调优指南&#xff1a;3步解锁锐龙处理器隐藏性能 【免费下载链接】RyzenAdj Adjust power management settings for Ryzen APUs 项目地址: https://gitcode.com/gh_mirrors/ry/RyzenAdj RyzenAdj是一款开源AMD锐龙处理器电源管理工具&#xff0c;通过直接与…

作者头像 李华
网站建设 2026/4/30 17:23:27

深入OpenWrt LuCI:一次HTTP请求如何变成你看到的Web页面?

深入OpenWrt LuCI&#xff1a;一次HTTP请求如何变成你看到的Web页面&#xff1f; 当你点击OpenWrt路由器管理界面上的"网络->接口"按钮时&#xff0c;背后发生了什么&#xff1f;这个看似简单的操作触发了一系列精妙的技术协作&#xff0c;从浏览器到uhttpd服务器…

作者头像 李华
网站建设 2026/4/30 17:22:54

对比直接使用原厂 API 体验 Taotoken 在路由容灾上的优势

Taotoken 路由容灾能力的使用体验 1. 接入 Taotoken 的背景 在我们的应用服务中&#xff0c;大模型 API 调用是核心功能之一。最初我们直接对接了单一厂商的原生 API&#xff0c;但在实际运行过程中发现&#xff0c;当该厂商服务出现临时波动时&#xff0c;我们的服务也会受到…

作者头像 李华