C++多态:静态多态(函数地址早绑定),动态多态(函数地址晚绑定)虚函数表,虚析构函数重写。

目录

一:多态的思想

二:静态多态(函数地址早绑定)

三:动态多态(函数地址晚绑定)

3.1:虚函数与纯虚函数

3.2:抽象类与函数重写

(1)抽象类

(2)函数重写

四:多态的本质

(1)虚函数表与虚函数表指针

五:析构函数的重写


一:多态的思想

父类的指针或引用可以指向子类对象。

对于子类son与son1来说,父类指针(b1)可以接收这两个子类实例化后的对象 。但是对于两个子类之间,他们并没有任何的关系,所以在使用son类指针去接收son1类对象时,编译器会报错,son1类型值不能用于初始化son类型的实体。这就是多态的核心了:父类的指针或引用可以接收他所有子类的类型对象。

但是多态也分为静态多态和动态多态,我们下面通过一些实例来了解一下他们间的区别

二:静态多态(函数地址早绑定)

class base1
{
public:
	void show()
	{
		cout << "父类中的show函数" << endl;
	}
};

class son :public base1
{
public:
	void show()
	{
		cout << "子类son中的show函数" << endl;
	}
};


class son1 :public base1
{
public:
	void show()
	{
		cout << "子类son1中的show函数" << endl;
	}
}; 

void do_work(base1* b)
{
	b->show();
}

我们在父类与两个子类中都实现一个show方法,然后创建一个全局函数,函数参数是父类的指针,那么我们在主函数中分别使用两个子类对象去调用这个do_work函数,发现最终的结果打印的都是“父类中的show函数".

这里就属于静态多态,函数地址在程序编译,还未运行时就已经绑定好了,绑定的就是父类中的show函数地址。 

三:动态多态(函数地址晚绑定)

首先呢,它的各种实现方式都和静态多态相同。唯一的区别就在于他引入了一个虚函数的概念,“virtual”。在父类中,我们使用这个关键字来修饰一下show函数,然后再次运行代码。

 可以看到,再次运行后,使用两个子类调用do_work函数时,确实调用了两个子类中各自的show函数。这里我们将被virtual修饰过的函数称为虚函数。

3.1:虚函数与纯虚函数

虚函数在上面的例子中已经了解过了,那么纯虚函数又是怎么一回事呢,纯虚函数与虚函数相同,就是一个普通成员函数,前面被virtual修饰,但是没有函数体,直接等于0. 

3.2:抽象类与函数重写

(1)抽象类

一个类中,只要存在一个纯虚函数那么就称这个类为抽象类,而抽象类是不能实例化对象的。因为类的对象是可以调用类内成员函数,那么如果有一个函数是纯虚函数,那么对象在调用这个纯虚函数,编译器根本不知道该干什么。

(2)函数重写

父类中的虚函数与纯虚函数都可以进行函数重写。(父类中纯虚函数子类必须重写,不然就算做抽象类)函数重写与函数重载是不同的概念,(这里就不解释函数重载了)

要进行函数重写,那么被重写的函数的函数名,函数返回类型,函数参数个数,顺序,类型都必须一致。

其实上面的动态多态中的show函数的例子,就是函数重写了,返回类型都i是void,都是无参函数,函数名都相同。

四:多态的本质

(1)虚函数表与虚函数表指针

这个概念与虚基类表,和虚基类表指针相似,如果想了解可以点进去看看

(1条消息) C++继承(二)多继承,菱形继承,继承中同名成员问题的解决,虚继承。虚基类表和虚基类表指针。_来年秋风起^的博客-CSDN博客https://blog.csdn.net/qq_51004011/article/details/125600180?spm=1001.2014.3001.5501

只要类中存在虚函数或纯虚函数,那么类内就会自动生成一个虚函数表指针,指向一张虚函数表,在这个虚函数表中,存放着类内所有虚函数的地址 。

当这个类被它的子类继承时,子类也会继承这个虚函数表指针,与虚函数表,(注意两张虚函数表不是同一张表,可以理解为复制了一张虚函数表交给子类的虚函数标配指针。)

现在只要子类中对父类的虚函数和纯虚函数进行函数重写,那么子类中重写后的函数地址就会将原来的函数地址覆盖掉。这样就实现了动态的多态。

多态性提供了接口与具体实现之间的另一层隔离。

当然一般来说多态实现的都是动态的多态。

五:析构函数的重写

在发生多态时,我们使用父类指针或者引用去操作子类对象,使用完这个对象后,对其进行析构时,它只会调用父类中的析构函数,并不会调用子类的析构函数。

所以当子类中有向堆区申请的空间时,就会出现内存泄漏的情况。那么我们就需要对父类的析构函数进行虚声明,并在子类中,提供自己的析构函数,那么在释放相应的子类对象时,就会调用相应的子类析构函数了。

  • 9
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值