虚函数及其实现

本文详细解析了虚函数的工作原理,包括如何在运行时动态调用,以及虚函数表的存储和使用方式。解释了虚函数依赖于对象调用和函数可寻址性的条件,说明了内联函数、构造函数和静态函数不能成为虚函数的原因,并介绍了可以设为虚函数的普通成员函数和析构函数。
摘要由CSDN通过智能技术生成

虚函数可以在运行的过程中动态编联,根据指针所指的对象,调用对应的函数

成为虚函数必须满足两个条件:

1.函数依赖于对象调用:因为虚函数是存储在虚函数表中,有一个虚函数指针指向虚函数表,要调用虚函数必须通过虚函数指针,虚函数指针是存储在对象中的。

2.函数必须可寻址,因为虚函数表中存放的是虚函数的入口地址

不能成为虚函数的函数

1.内联函数:在内联函数的调用点将其展开,不能产生函数符号,所以不能把它存入虚表

2.构造函数:只有在调用完构造函数之后才能生成对象,虚函数依赖于对象的调用,要是将构造函数设为虚函数的话就不能生成对象了

3.静态函数:静态函数依赖于类,不依赖于对象,所以不能存放在虚表中

可以设为虚函数的函数:

1.普通的成员函数

2.析构函数:因为在调用析构函数之前已经建立了对象,并且析构函数可以取地址

析构函数必须设为虚函数的情况:

基类指针指向了派生类的对象时,必须将基类的析构函数设为虚函数。

编译器会将虚函数表的指针存放在对象实例中最前面的位置,通过对象实例的地址就可以得到虚函数指针的地址,通过遍历虚函数指针就可以调用虚函数

class Base {
public:
            virtual void f() { cout << "Base::f" << endl; } 

            virtual void g() { cout << "Base::g" << endl; } 

            virtual void h() { cout << "Base::h" << endl; }
};
typedef void(*Fun)(void); 

          Base b;

           Fun pFun = NULL;

            cout << "虚函数表地址:" << (int*)(&b) << endl;

            cout << "虚函数表 — 第一个函数地址:" << (int*)*(int*)(&b) << endl;

            // Invoke the first virtual function 

            pFun = (Fun)*((int*)*(int*)(&b));

            pFun();

输出:
虚函数表地址:0012FED4

虚函数表 — 第一个函数地址:0044F148

Base::f

通过强行把&b转成int *,*取得虚函数表的地址,然后,再次取址就可以得到第一个虚函数的地址了,也就是Base::f()
调用Base::g()和Base::h(),其代码如下:

            (Fun)*((int*)*(int*)(&b)+0);  // Base::f()

            (Fun)*((int*)*(int*)(&b)+1);  // Base::g()

            (Fun)*((int*)*(int*)(&b)+2);  // Base::h()

在这里插入图片描述
·是结束标志
参考blog主要看图
主要包括单继承无覆盖、单继承覆盖、多重继承、多重继承有覆盖的情况。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值