动态多态和静态多态(C++)_静态多态和动态多态-程序员宅基地

技术标签: C++  c++  多态  

多态:即一个接口多种实现方式;C++中的多态分为两种:静态多态与动态多态

一、静态多态:也成为编译时的多态;在编译时期就已经确定要执行了的函数地址了;主要有函数重载和函数模板(这里只写函数重载)


(1)重写基类函数(方法)

C++中当我们一个类继承于一个另一个类时,我们在派生类中不想使用基类中的函数,想重新写一个同名函数,这是被允许的;因此我们的基类与派生类可以有同名的函数;例如我们现在有一个类中已经有了一个函数名为show无参的函数,我们在派生类中再写一个名为show函数,这叫函数重载也称为覆盖和重写;


测试代码:

#include <iostream>

using namespace std;

class AA
{
    
public:
	void show(){
    
		cout << "我是show1" << endl;
	}	
};

class BB :public AA
{
    
public:
	void show(){
    
		cout << "我是show2" << endl;
	}	
};

int main()
{
    
	BB a;
	a.show();	//输出show2
    //a.show(); //此时会报错:没有匹配的函数,因为已经被重写了基类中的函数
	//a.AA::show();//正常输出AA类中的数据

	return 0;
}

运行结果:
静态多态

因为此时派生类中重写了父类中的同名函数,因此在BB类中看到的show的函数是派生类中的重写后的show函数;其实AA类中的show函数还是存在的,并不是说重写了函数后,它就不存在了因此我们还是可以通过指定类中=名去调用AA类中的函数



二动态多态:即动态绑定,在运行时才去确定对象类型和正确选择需要调用的函数,一般用于解决基类指针或引用派生类对象调用类中重写的方法(函数)时出现的问题

测试代码:

#include <iostream>

using namespace std;

class AA
{
    
public:
	AA(){
    
                cout << "AA()的构造函数"<<endl;
    }

    ~AA(){
    
                 cout << "AA()的析构函数"<<endl;
    }

	void show(){
    
		cout << "我是show1" << endl;
	}	
};

class BB :public AA
{
    
public:
	BB(){
    
	               cout << "BB()的构造函数"<<endl; 
	}
	   
      ~BB(){
    
              cout << "BB()的析构函数"<<endl; 
      }

	void show(){
    
		cout << "我是show2" << endl;
	}	
};

int main()
{
    
	//使用指针时在析构时只会调用基类中地析构函数
	//AA * d = new BB();
    //d->show();	
	
	BB a;
	AA &b = a;
	b.show();
	
	//delete d; //使用指针时用于释放内存
	return 0;
}

运行结果:
(1)引用
在这里插入图片描述
(2)指针:
在这里插入图片描述

很明显该程序执行的结果并没有按照AA类型的指针指向的真正的内容去执行对应的代码,而我们是想要编译器能够正确地知道AA &b(或指针)所指向地内容是什么类型的而不是根据当前指针或引用的类型去判断调用什么函数,此时我们实现这种动态多态就需要通过使用关键字virtual来实现;

(1)virtual 修饰的函数称为虚函数,其是通过使用virtual关键字后产生一个虚表(虚函数表),然后每一个对象会创建一个虚表,虚表存放当前对象拥有的虚函数
(2)当虚函数被创建后就会被放入虚表,当派生类重写虚函数后,创建派生类对象时会把虚表内的对应函数地址换成派生类中重写的函数地址

虚表

注意:
(1)每次执行虚函数都会去重新去替换掉原来虚表的位置
(2)当使用虚函数后原来函数的存放位置会分配一个指针用于指向虚表中函数的地址
(3)一个对象可以拥有多个虚函数,但只能有一个虚表

测试代码:

#include <iostream>

using namespace std;

class AA
{
    
public:
        AA(){
    
                cout << "AA()的构造函数"<<endl;
    }   

    ~AA(){
    
                 cout << "AA()的析构函数"<<endl;
    }   

        virtual void show(){
    
                cout << "我是show1" << endl;
        }    
};

class BB :public AA
{
    
public:
        BB(){
    
                       cout << "BB()的构造函数"<<endl;
        }

      ~BB(){
    
              cout << "BB()的析构函数"<<endl;
      }

        void show(){
    
                cout << "我是show2" << endl;
        }
};

int main()
{
    

        BB a;
        AA &b = a;
        b.show();

        return 0;
}

运行结果:

在这里插入图片描述
关于虚表地址:
在这里插入图片描述
此时就会根据对象去正确地选择函数调用了


《纯粹个人理解,有错的地方麻烦提醒一下;非常感谢》

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/takashi77/article/details/108908680

智能推荐

多线程编程学习::POSIX 多线程基础(三)-程序员宅基地

文章浏览阅读305次。注:本文涉及到的 glibc 版本为 2.11,若无特别说明,.表示 glibc-2.11 源代码目录,本文为 /usr/src/glibc-2.11。基本概念临界区:一个存取共享资源的代码段,而这些共享资源无法同时被多个线程访问;即影响共享数据的代码段。线程同步方法确保对相同/相关数据的内存访问互斥地进行,即一次只能允许一个线程写数据,其他线程必须等待Pthrea

汽车电子学习笔记---AutoSAR之BSW---NVRAM Manager(二)_nvm_geterrorstatus-程序员宅基地

文章浏览阅读3.5k次,点赞9次,收藏62次。汽车电子学习笔记—AutoSAR之BSW—NVRAM Manager(二)- 1、RAM Block dataRAM 状态转换图RAM状态转换说明1)上电最初状态:UNINITIALIZED2)初始化后(NvM_Init):INVALID / UNCHANGED3)NvM_ReadAll后更新:VALID/UNCHANGED,在这种状态下,WriteAll是不允许的4)调用NvM_SetRamBlockStatus()可以设置RAM状态:参数为true, VALID / CHANG_nvm_geterrorstatus

Ubuntu samba 服务的使用_unbuntu samba常用使用指令_Max.Chen的博客-程序员宅基地

文章浏览阅读1.7k次。1.sudo vim /etc/samba/smb.conf 修改配置文件,max是用户名且valid users里必须包含具有root权限的,否则windows中会提示无法访问在最后添加如下[max]comment = maxbrowseable = yespath = /home/maxcreate mask = 0700directory mask = 0700valid users = maxforce user = maxforce group = maxpublic =_unbuntu samba常用使用指令

Nmap-07:Nmap使用特定网卡进行探测_nmap 扫描选择本地网卡-程序员宅基地

文章浏览阅读2.8k次。目录1.情景介绍2.指定网卡进行探测1.情景介绍 Nmap是一款可拓展性非常强的工具,并且有些NSE脚本支持嗅探,但是这种功能需要网卡支持混杂模式才可以。或者当计算机上有两张网卡,并且两张网卡对应的不同的网络。 Nmap中提供了切换使用特定网卡进行探测的参数 -e2.指定网卡进行探测..._nmap 扫描选择本地网卡

kali linux命令行模式下连接wifi_kali连接wifi-程序员宅基地

文章浏览阅读3.6k次。nmcli dev wifi con “ssid” password “ssidpassword”ssid换成自己的SSIDssidpassword换成自己的wifi密码查看可用热点列表:nmcli dev wifi list如果还不行的话,查网卡状态iwfconfigifconfig wla0 upreboot然后再次查看网卡状态nmcli dev wifi con “ssi..._kali连接wifi

网络营销的方式_搜索引擎营销是通过开通搜索引擎竞价,让用户搜索到相关关键词,进一步了解所需-程序员宅基地

文章浏览阅读496次。网络营销的方式1、搜索引擎营销:即SEM(通常以PPC为代表),通过开通搜索引擎竞价,让用户搜索相关关键词,并点击搜索引擎上的关键词创意链接进入网站/网页进一步了解他所需要的信息,然后通过拨打网站上的客服电话、与在线客服沟通或直接提交页面上的表单等来实现自己的目的。2、搜索引擎优化:即SEO,指的是在了解搜索引擎自然排名机制的基础上,使用网站内及网站外的优化手段,使网站在搜索引擎的关键词排..._搜索引擎营销是通过开通搜索引擎竞价,让用户搜索到相关关键词,进一步了解所需

随便推点

Keras ImageDataGenerator用于数据扩充/增强的原理及方法_数据扩充和数据增强-程序员宅基地

文章浏览阅读5.3k次,点赞6次,收藏29次。在这篇博客中,您了解了数据扩充/增强以及如何通过Keras的ImageDataGenerator类应用数据扩充。有三种数据增强类型,默认情况下,Keras的ImageDataGenerator该类执行就地/即时数据扩充。数据增强是正则化的一种形式,使我们的网络可以更好地将其推广到我们的测试/验证集。在训练中不应用数据增强会导致过度拟合。应用数据增强,可以进行平滑的训练,避免过度拟合以及拥有更高的准确性/更低的损失。尽量在所有的训练中都使用数据增强。..._数据扩充和数据增强

4.python中的list集合_python list集合-程序员宅基地

文章浏览阅读1.6k次。1.list:python内置的有序的集合2.有两种声明list的方式:list()和[] list1=['liko','alan'] list2=list(['liko','alan']) print(type(list1),type(list2))&lt;class 'list'&gt; &lt;class 'list'&gt;3.使用len函数获取list的长度 print(le..._python list集合

DBA七个必备知识点-程序员宅基地

文章浏览阅读392次。DBA含义 数据库管理员,英文是Database Administrator,简称DBA。这个职位对不同的人意味着不同的意义。一个小的软件开发工作室和一个分工高度明细的大公司相比,DBA的职责来得更加宽泛一些。一个公司,不管..._dba应该掌握什么知识

小记(1)偷影子的人-程序员宅基地

文章浏览阅读158次。偷影子的人前言想做个勤奋的日更博主,立字为证,连更百日。前些天,趁阳光正好,和室友去老校区看风景,碰巧校青协在做活动,被问最近读过什么书籍,明明刚读完这本《偷影子的人》,但却一句也讲不出,所以只好拒绝。所以从这本书的书评开始,向百日进发。只是读完之后的一些感想想要摆脱空闲时间都去打游戏的坏毛病,所以我带了几本书放到自习室,想着学习之余能够拜读经典,放松心情(其实还是不想学习呜呜呜)。本来只是晚上闲来无事(不想学习)随意翻看,可事实是,一口气直接将书看完,意犹未尽。这本书被称为是一部关于得到与失

安装Tomcat后iServer启动失败_iserver 启动失败-程序员宅基地

文章浏览阅读595次。java开发环境安装Tomcat后会导致iServer启动失败,主要是由于iServer调用了Tomcat的环境变量导致的,解决办法很简单,改变量名。方法1:改iServer的变量名iserver主目录下找到这三个文件bin/startup.batbin/shutdown.batcatalina.bat以文本方式打开并将所有CATALINA_HOME替换成CATALINA_HOME2,所有CATALINA_BASE替换成CATALINA_BASE2并保存。CATALINA_HOME2和CAT_iserver 启动失败

解决java.net.BindException: Address already in use: JVM_Bind问题-程序员宅基地

文章浏览阅读3.6k次。问题描述:解决办法:由于1099进程端口号被占用,这里要查出进程,将进程结束:netstat -ano | findstr 1099taskkill -pid 7792