C++中的虚函数

.前言
虚函数是实现动态绑定的函数,在C++中虚函数的作用是实现多态的机制。
常用情景是需要用基类类型的指针指向其派生类的实例,然后通过基类指针去调用派生类实例的成员函数。

.情景
我们希望定义一个基类和多个派生类,他们都有同样的名字的成员函数,但实现细节不同,我们希望通过一个通用函数根据传入的类的对象去调用各类的函数。

代码:

#include <iostream>
using namespace std;
class Base1//基类Base1定义
{
public:
	void display()const
	{
		cout << "Base1::display()" << endl;
	}
};

class Base2:public Base1//公有派生类Base2定义
{
public:
	void display()const
	{
		cout << "Base2::display()" << endl;
	}
};

class Derived:public Base2//公有派生类Derived定义
{
public:
	void display()const
	{
		cout << "Derived::display()" << endl;
	}
};

void fun(Base1* ptr)  //参数为指向基类对象的指针
{
	ptr->display();   //对象指针->成员名
}
int main()
{
	Base1 base1;        //声明Base1类对象
	Base2 base2;        //声明Base2类对象
	Derived derived;    //声明Derived类对象

	fun(&base1);        //用Base1对象的指针调用fun函数
	fun(&base2);        //用Base2对象的指针调用fun函数
	fun(&derived);      //用Derived对象的指针调用fun函数

	return 0;
}

我们的期望输出是:

Base1::display()
Base2::display()
Derived::display()

实际结果:

Base1::display()
Base1::display()
Base1::display()

因此,不要重新定义继承而来的非虚函数

不成功原因:
在编译阶段,编译器根据指针无法判断在运行时它会指向什么样的对象,所以指针是什么类型的,它就会调用对应类型的成员函数。
即在函数void fun(Base1* ptr)我们给指针定义的是Base1的类型,因此它只能调用Base1的 函数。

既然在编译阶段无法确定要调用的类的函数,你们我们可以在运行时再确定——“虚函数”

修改后:

class Base1//基类Base1定义
{
public:
	virtual void display()const
	{
		cout << "Base1::display()" << endl;
	}
};

结果:

Base1::display()
Base2::display()
Derived::display()

.概括
用virtual关键字说明的函数就是虚函数
虚函数是实现运行时多态性基础(而静态多态性即编译阶段,则靠重载完成)
C++中的虚函数是动态绑定的函数
虚函数必须是非静态的成员函数,虚函数经过派生之后,就可以实现运行过程中的多态。

.什么函数可以是虚函数
一般成员函数可以是虚函数
构造函数不能是虚函数
析构函数可以是虚函数

.格式即其他相关事项
虚函数的声明
virtual 函数类型 函数名(形参表)

虚函数声明只能出现在类定义的函数声明原型声明中,而不能在成员函数实现的时候

在派生类类中可以对基类的成员函数进行覆盖

虚函数一般不声明为内联函数,因为对虚函数的调用是需要动态绑定的,而对内联函数的处理是静态的。(同样也不能加static,不过反正也加不了)

.虚析构函数
如果你打算允许其他人通过基类指针调用对象的析构函数(通过delete这样做是正常的),就需要让基类的析构函数成为虚函数,发展执行delete的结果是不明确的。

.另:虚函数实现原理
虚函数是依靠一张虚表(Virtual Table)来实现的,简称为V-Table。这张表解决了继承、覆盖的问题,保证其容真实反应实际的函数。

.虚表
每个多态类都有一个虚表
虚表中有当前类的各个虚函数的入口地址
每个对象有一个指向当前类的虚表的指针(虚指针vptr)

.动态绑定的实现
构造函数中为对象的虚指针赋值
通过多态类型的指针或引用调用成员函数时,通过虚指针知道虚表,进而找到所调用的虚函数的入口地址
通过入口地址调用虚函数

关于如何获取虚表地址和虚函数地址可参考:https://blog.csdn.net/qianghaohao/article/details/51356718

图解:
在这里插入图片描述

相关可参考:https://xiaomaweifu.blog.csdn.net/article/details/81326699

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值