C++虚函数 一

虚函数

虚函数的作用

面向对象中一个非常重要的概念叫多态,指的是
使得一个基类指针指向一个派生类对象,当调用基类和派生类共有的函数时,最终调用的是派生类的函数。
如下

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

class Derived : public Base{
public:
	virtual void f(){
		cout<<"Derived call f()";
	}
};
int main(){
	Base* pb = new Derived();
	pb->f();
}

最终结果如下
在这里插入图片描述

虚函数的实现原理

实现该原理的原因是如果类中定义了虚函数,则会在生成对象时生成一个虚函数表指针,这个指针指向虚函数表,虚函数表中存在着类中定义着指向虚函数的指针。

通过这些虚函数,我们可以调用虚函数。

而派生类在继承基类时,也会生成一张虚函数表,虚函数表中存在着父类和自己定义的虚方法。如果重写了基类的虚方法,则会在虚函数表中用派生类重写的方法覆盖其基类原来的虚函数方法。

虚函数实现原理的验证

首先验证
如果类中定义了虚函数,则会在生成对象时生成一个虚函数表指针

class A{
public:
	A(){cout<<"call A()"<<endl;}
	~A(){cout<<"call A()"<<endl;}
};
class B{
public:
	B(){cout<<"call B()"<<endl;}
	
	virtual void virtualBB(){cout<<"call virtualBB()"<<endl;}
	virtual void virtualB(){cout<<"call virtualB()"<<endl;}
	virtual ~B(){cout<<"call ~B()"<<endl;}
	
};
int main(){
A a;
	B b;
	cout<<"sizeof(a) = "<<sizeof(a)<<endl;//it should be one size
	cout<<"sizeof(b) = "<<sizeof(b)<<endl;//it should be eight size, a virtual pointer size
}

在这里插入图片描述

再验证
派生类在继承基类时,也会生成一张虚函数表,虚函数表中存在着父类和自己定义的虚方法

//author: Solitude
//date: 2021-09-29
//purpose: validate the concept of virtual 

#include <iostream>
using namespace std;

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

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

//validate the concept 
typedef void (*PF)();
class A{
public:
	A(){cout<<"call A()"<<endl;}
	~A(){cout<<"call A()"<<endl;}
};
class B{
public:
	B(){cout<<"call B()"<<endl;}
	
	virtual void virtualBB(){cout<<"call virtualBB()"<<endl;}
	virtual void virtualB(){cout<<"call virtualB()"<<endl;}
	virtual ~B(){cout<<"call ~B()"<<endl;}
	
};

int main(){
	#if 0
	Base* pb = new Derived();
	pb->f();
	#endif
	
	#if 1
	A a;
	B b;
	cout<<"sizeof(a) = "<<sizeof(a)<<endl;//it should be one size
	cout<<"sizeof(b) = "<<sizeof(b)<<endl;//it should be eight size, a virtual pointer size
	PF pf;
	pf =  (PF)*((int*)*(int*)(&b)+0);
	pf();
	pf =  (PF)*((int*)*(int*)(&b)+2);
	pf();
	#endif
	return 0;
}

结果如下在这里插入图片描述
typedef void (PF)(); 作用为定义一个函数指针,定义这个指针的目的是用来调用虚函数表中虚函数指针指向的虚函数。
(PF)
((int*)(int)(&b)+0);用法有点绕,我解释一下
咱们一步步拆解

(int*)(&b)
(&b)为虚函数指针的地址,我们将之转化为int*类型的指针,这样就获得了一个指向虚函数表的指针。

(int*)(int)(&b)
再将问题变复杂一点,(int)(&b)使得我们得到了虚函数表第一个虚函数指针的位置,我们将之转化为int*类型的指针,这样就获得了一个指向虚函数的指针。

(PF)((int)(int)(&b)+0)
再复杂一点,
((int)(int)(&b)+0)使得我们得到了虚函数表中指向的第一个虚函数的位置,我们再用(PF)将之转化为函数指针的形式。这样我们就得到了函数 virtualBB()的函数指针。
期间加0,加2是为了用得是指针加法,目的是在虚函数表中找到我们的虚函数。

coolshell 陈皓

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值