【C++进阶】多态的理解

news2024/9/21 0:42:08

一.多态是什么

多态是在不同继承关系的类对象,去调用同一函数,产生了不同的行为。

对于多态,不同的对象传过去,会调用不同的函数

即多态调用看的是指向的对象

//A,B类中的func函数是个多态
class A
{
public:
	virtual void func()
	{
		cout << "A->func" << endl;
	}
};

class B :public A
{
public:
	virtual void func()
	{
		cout << "B->func" << endl;
	}
};

动态绑定和静态绑定

多态分为两种:

        1.静态绑定,也称为静态多态,是在程序编译阶段确定的,例如:函数重载和模板

        2.动态绑定,也称为动态多态,是在程序运行阶段确定的,根据具体拿到的类型确定程序的               具体行为,调用具体的函数。


二.虚函数

虚函数:即被virtual修饰的类成员函数称为虚函数

虚函数一般是存在代码段(常量区)的,可能不同的编译器会不一样。

纯虚函数与抽象类

在虚函数的后面写上 =0 ,则这个函数为纯虚函数。包含纯虚函数的类叫做抽象类(也叫接口
类),抽象类不能实例化出对象。派生类继承后也不能实例化出对象,只有重写纯虚函数,派生
类才能实例化出对象。

抽象类的作用:抽象类强制重写了虚函数,另外抽象类体现出了接口继承关系。

接口继承和实现继承

实现继承:普通函数的继承是一种实现继承

接口继承:虚函数的继承是一种接口继承,如果不实现多态,不要把函数定义成虚函数。

虚函数与静态成员函数

静态成员函数没有this指针,使用类型::成员函数的调用方式无法访问虚函数表,所以静态成员函数无法放进虚函数表,即静态成员函数不能设置成虚函数

虚函数与 inline 函数

inline函数可以设置成虚函数,不过编译器就忽略inline属性,这个函数就不再是inline,因为虚函数要放到虚表中去。


三.多态的条件

虚函数重写(覆盖)条件

             a.是虚函数,即要有 virtual

             b.虚函数满足三同(返回值,函数名,参数列表相同)即构成重写

    例外:

             a.派生类可以不加 virtual  ,因为派生类已经继承了基类的 virtual;

             b.协变(基类虚函数返回基类对象的指针或者引用,派生类虚函数返回派生类对象                    的指针或者引用时,称为协变)

构成条件

1.调用的函数是重写的虚函数

2.必须通过基类的指针或者引用调用虚函数

重写析构函数

其实编译后析构函数的名称统一处理成destructor,此时析构函数的函数名相同,参数列表也相同,再加上 virtual  修饰,此时就重写了基类和派生类中的析构函数,即构成了多态。

结论

析构函数建议设置成虚函数,因为有时可能利用多态方式通过基类指针调用子类析构函        数,尤其是父类的析构函数强力建议设置为虚函数,这样动态释放父类指针所指的子类      对象时,能够达到析构的多态。

重载,重定义(隐藏)与重写

重载:在同一作用域,函数名相同,返回值可以不同,参数列表必须不同

重定义(隐藏):在不同的作用域,一个在基类,一个在派生类,只要函数名相同就构成重定义

重写:1.在不同的作用域,一个在基类,一个在派生类;

           2.都必须是虚函数

           3.满足三同(函数名,返回值,参数列表相同(协变除外))

总结

1.重写比重定义的条件更加严苛;

2.两个基类和派生类的同名函数,不是重定义就是重写

class A
{
public:
	virtual void func()   //func函数重写
	{
		cout << "A->func" << endl;
	}
};

class B :public A
{
public:
	virtual void func()
	{
		cout << "B->func" << endl;
	}
};

void test(A& a)   //基类引用
{
	a.func();
}

int main()
{
	A a;
	B b;
	test(a);   //传A的对象,调用A类的函数
	test(b);   //传B的对象,调用B类的函数

	return 0;
}

   override 和 final

override:检查派生类虚函数是否重写了基类某个虚函数,如果没有重写编译报错;

final:修饰虚函数,表示该虚函数不能再被重写

class A
{
public:
    virtual void func1() final  {}   //func1不能被重写
    virtual void func2() {}
  
};

class B:public A
{
public:
    virtual void func2() override {}   //检查 func2 是否正确重写
};

四.多态的原理

虚函数表

其实基类和派生类的虚函数都会被放进虚函数表(简称虚表)里,类实例化出对象后会生成一个指针(_vfptr)指向虚函数表,其实虚函数表就是一个函数指针数组,里面存着虚函数的地址,一般情况这个数组最后面放了一个nullptr。

同一个类的对象共享一个虚表

 打印虚表

因为虚表指针一般存在对象的前4个字节(64位则为前8个字节),我们可以通过强制类型转换拿到这个虚表指针。

typedef void (*FUNC_PTR) ();    //重定义函数指针

void print(FUNC_PTR* table)
{
	for (size_t i = 0; table[i] != nullptr; i++)   //需要注意每次运行时最好重新生成以下解决方 
                                                   //案,因为多次编译vs可能就没有这个nullptr了
	{
		printf("%p : ", table[i]);

		FUNC_PTR f = table[i];
		f();   //调用函数指针所指向的函数
	}

	cout << endl;
}

class A
{
public:
	virtual void func1()
	{
		cout << "A->func1" << endl;
	}

	virtual void func2()
	{
		cout << "A->func2" << endl;
	}
};

int main()
{
	A a;
	int vft1 = *((int*)&a);
	print((FUNC_PTR*)vft1);
	return 0;
}

观察打印结果我们可以发现,打印的就是对象里的所有虚函数。

 

虚表生成

虚表指针其实是在初始化列表阶段初始化的,所以构造函数不能设置成虚函数;

虚表生成:

                  a.先将基类中的虚表内容拷贝一份到派生类虚表中

                  b.如果派生类重写了基类中某个虚函数,用派生类自己的虚函数覆盖虚表中基类的虚函                       数;

                  c.派生类自己新增加的虚函数按其在派生类中的声明次序增加到派生类虚表的最后


🐬🤖本篇文章到此就结束了, 若有错误或是建议的话,欢迎小伙伴们指出;🕊️👻

😄😆希望小伙伴们能支持支持博主啊,你们的支持对我很重要哦;🥰🤩

😍😁谢谢你的阅读。😸😼

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/802593.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

自制Nuget包(C#)

自制Nuget包 自制C# Nuget包。 目的&#xff1a; 生成一个可以通过Nuget管理自动应用的包&#xff0c;生成效果如图&#xff1a; 步骤&#xff1a; 整个制作过程分为两步&#xff1a;第一步制作Nuget包&#xff0c;第二步上传Nuget包到Nuget网站&#xff08;地址&#xf…

Redis实战(2)——互斥命令用于构建分布式锁

1 什么是分布式锁 在单体应用中&#xff0c;线程锁是可以让多个线程串行执行一段代码逻辑的。不过在集群环境或者是分布式的环境下&#xff0c;线程锁无法保证线程串行运行&#xff0c;从而出现线程安全的问题。 根本的原因在于&#xff0c;在 集群分布式环境下 \textcolor{r…

F12 浏览器调试模式页面刷新 network 日志刷新消失的解决办法

每次请求刷新后都把之前的请求记录刷新掉了&#xff0c;把preserve log勾选上后&#xff0c;所有的请求都会保留&#xff0c;再也不怕抓不到记录了。

配置 gitlab https 访问

文章目录 1. 备份2. 生成SSL证书3. 配置文件4. 重启5. 访问 1. 备份 docker exec -ti gitlab-ce gitlab-rake gitlab:backup:create2. 生成SSL证书 yum install openssl openssl-devel -y mkdir /data/gitlab/config/ssl ; cd /data/gitlab/config/ssl### 生成证书 openssl…

郑州Sectigo DV通配符SSL证书

我们在浏览器访问网页时或许不会注意到网站是http还是https链接&#xff0c;但是一定能注意到浏览器给我们展示的“不安全”警告&#xff0c;警告访问者网站未加密&#xff0c;访问网站会有泄露隐私的危险。SSL证书能将网站链接由http转为https&#xff0c;对网站传输数据加密&…

数据科学复现

片段 线性回归建模步骤.py 用sklearn做简单的一元线性回归.py 红用逻辑回归实现红酒数据分类py 高斯朴素贝叶斯分类py

uni-app如何生成正式的APK

第一步&#xff1a; 进入dcloud官网https://dcloud.io/&#xff0c;点击开发者后台进入登录注册页面 第二步&#xff1a;登录之后跳到项目列表&#xff0c;选择自己想要打包的项目 点击进去如果没有生成证书&#xff0c;点击生成证书&#xff0c;如果显示证书已生成就不用管了…

什么样的程序员在35岁后仍然保持竞争力?

作为程序员&#xff0c;大家肯定都听说过程序员的35岁危机&#xff0c;有的人刚入职程序员这个岗位就开始为自己的未来担忧&#xff0c;然而&#xff0c;与其担心自己35岁以后被优化掉&#xff0c;不如现在想想&#xff0c;怎么让自己到了35岁以后在这个岗位上依旧有竞争力。今…

【Python】在PyCharm中安装 ChatGPT 插件,让 AI 帮助我们写代码,从此代码再无报错,小白也能轻易上手!!!

前言 ChatGPT是目前最强大的AI&#xff0c;不仅能够聊天、写小说&#xff0c;甚至码代码也不在话下。 但是在国内要使用chatgpt很麻烦&#xff0c;国内一家团队开发了一款idea插件NexChatGPT&#xff0c;用数据代理的方式&#xff0c;让我们在国内也能轻松的使用chatgpt。 没…

【图像去噪】基于进化算法——自组织迁移算法(SOMA)的图像去噪研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

亚马逊云科技联合霞光社发布《2013~2023中国企业全球化发展报告》

中国企业正处于全球聚光灯下。当企业全球化成为时代发展下的必然趋势&#xff0c;出海也从“可选项”变为“必选项”。中国急速扩大的经济规模&#xff0c;不断升级的研发和制造能力&#xff0c;都在推动中国企业不断拓宽在全球各行业的疆域。 过去十年&#xff0c;是中国企业…

Unity XML1——XML基本语法

一、XML 概述 ​ 全称&#xff1a;可拓展标记语言&#xff08;EXtensible Markup Language&#xff09; ​ XML 是国际通用的&#xff0c;它是被设计来用于传输和存储数据的一种文本特殊格式&#xff0c;文件后缀一般为 .xml ​ 我们在游戏中可以把游戏数据按照 XML 的格式标…

SOLIDWORKS 运行缓慢?了解如何诊断SOLIDWORKS大型装配性能问题?

在打开装配时&#xff0c;您的SOLIDWORKS运行缓慢吗&#xff1f;或者不仅打开时间慢&#xff0c;每次点击、旋转或缩放都会产生延迟。 好消息是&#xff0c;我们是可以改善装配加载性能的&#xff0c;困难的部分是需要知道从哪里入手。本文中&#xff0c;我们将研究如何诊断SO…

这几个习惯,让我成为了高阶项目经理

大家好&#xff0c;我是老原。 每个大佬都有每个大佬不同的习惯。但是优秀的大佬之间是有共性的。 当我们把他们的共性当做一种“习惯”来训练自己&#xff0c;有没有可能也把自己培养成大佬 就像你一开始不知道怎么预设风险、沟通和团队协调不够好&#xff1b; 有的人就可…

提升团队协作效率的秘诀!项目管理系统来帮忙!

在疫情的影响下&#xff0c;许多企业受到了经济的影响。企业产值和人员的减少需要提高现有员工的工作效率。项目中的团队合作是提高企业产值的重要组成部分。如何提高项目管理中员工的团队合作效率已成为困扰许多管理者的难题。 许多管理者在领导团队进行项目管理时无法有效地管…

Json-Server模拟服务端接口数据

vue2创建项目&#xff1a; 进入空文件夹 shift右键 进入PowerShell 执行命令&#xff1a; vue init webpack "项目名" 安装json-server npm install -g json-server 查看版本号 json-server -v 创建json数据&#xff0c;并在任意一个文件夹中执行命令 jso…

更安全,更省心丨DolphinDB 数据库权限管理系统使用指南

在数据库产品使用过程中&#xff0c;为保证数据不被窃取、不遭破坏&#xff0c;我们需要通过用户权限来限制用户对数据库、数据表、视图等功能的操作范围&#xff0c;以保证数据库安全性。为此&#xff0c;DolphinDB 提供了具备以下主要功能的权限管理系统&#xff1a; 提供用户…

【主成分分析(PCA)- 鸢尾花】

主成分分析&#xff08;PCA&#xff09; 摘要 在现代数据科学中&#xff0c;维度灾难常常是数据处理与分析的一大难题。主成分分析&#xff08;PCA&#xff09;是一种广泛使用的数据降维技术&#xff0c;它通过将原始数据转换为新的低维空间&#xff0c;保留最重要的信息&…

25岁的Java工程师,6个月顺利转行人工智能

曾经我是一名Java开发者&#xff0c;在过去的日子里&#xff0c;经历了夜以继日的加班、浑浑噩噩的摆烂。 如今&#xff0c;作为一名从博学谷毕业的人工智能从业者&#xff0c;职业生涯再度焕发活力&#xff0c;生活也变得非常愉快。 接下来&#xff0c;我将转变前后的这段经…