C++ - 初识多态

一、什么是多态

1.我们知道,面向对象语言都具有抽象、封装、继承、多态这几大特性,当然C++也不例外。
2.对于面向对象语言,多态简单来说就是同一接口,产生不同形态
3.实现多态的目的是为了一个方法可以被不同的对象调用,从而达到代码重用。避免重复造轮子。

多态分为静多态和动多态
1.静多态:在编译的时候就确定了函数的地址,然后call就调用了。
2.动多态:首先需要取到对象的首地址,然后再解引用取到虚函数表的首地址后,再加上偏移量才能找到要调的虚函数,然后call调用。

二、实现多态的条件

1.基类中被调用的函数必须是虚函数(virtual 关键字)。
2.必须有继承,并且必须由基类对象的指针或引用虚函数。
3.派生类必须对基类中的虚函数进行重写(重写要满足函数名、返回值、参数列表都相同)

补充:

1.函数名前增加 virtual 关键字,会增加类的大小,如果有一个虚函数,类的大小就会多4个字节(32位系统),多出来的4个大小即是虚函数表指针。它指向一张虚表,虚表里存放着每个虚函数的首地址。
在这里插入图片描述
2. 用子类的地址给父类的指针赋值后,指针永远只能访问父类的那部分数据(利用多态访问到的子类的函数是父类函数被替换得到)。
3.同名隐藏:子类的 fun 函数隐藏了父类所有的同名 fun 函数,不关心函数的返回值和参数,只关心函数的名字是否相同。
在这里插入图片描述

三、抽象类

3.1 概念

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

class Car
{
    
    
public:
	virtual void Drive() = 0;
};
class Benz :public Car
{
    
    
public:
	virtual void Drive()
	{
    
    
 		cout << "Benz Car" << endl;
 	}
};
int main()
{
    
    
	Car* pBenz = new Benz;
	pBenz->Drive();
	return 0;

3.2 接口继承和实现继承

普通函数的继承是一种实现继承,派生类继承了基类函数,可以使用函数,继承的是函数的实现。虚函数的继承是一种接口继承,派生类继承的是基类虚函数的接口,目的是为了重写,达成多态,继承的是接口。所以如果不实现多态,不要把函数定义成虚函数。

四、多态的实现原理

动态多态是利用虚函数实现的。在类中如果出现virtual关键字,那么这个类的大小将会多出一个指针的大小(32位4字节,64位8字节),多出来的这个指针(_vfptf)指向函数指针数组的首地址,我们称这个函数指针数组为虚函数表。
子类在继承基类时,会连同虚函数表一起继承,如果子类重写基类的虚函数,则会覆盖掉虚函数表中的函数地址,然后利用赋值兼容规则用子类给基类的指针赋值时后,利用基类指针访问某个虚函数时,就可以调用子类的方法。这就是可以调用子类对象方法的根本原因。

猜你喜欢

转载自blog.csdn.net/qq_43579888/article/details/113354491