C++深度探索虚函数(虚函数指针)

         代码描述:定义一个Person类为基类, ChinesePer 类与EnglishPer类都继承于此基类。

class Person
{
public:
	void speak() {
		cout << "说人话" << endl;
	}
private:
	int m_type = 1 ;
};

class ChinesePer :public Person {
public:
	void speak() {
		cout << "说中国话chinese..." << endl;
	}
};

class EnglishPer :public Person {
public:
	void speak() {
		cout << "说英国话english..." << endl;
	}
};

        先看看此时各个类占用的内存信息:

int main() {
	int person_size = sizeof(Person);
	int Chineseper_size = sizeof(ChinesePer);
	int Englishper = sizeof(EnglishPer);

}

        可以看到三个类的大小都为4个字节,占用的情况就是 类中的m_type变量。

        将基类中的 speak() 函数加上virtual关键字 ,成为虚函数后再次查看内存字节大小:

         可以看到多出了4个字节大小的空间(X86),三个类的大小都为 8。其实就是多出了一个指针的大小,4个字节 ,创建一个子类对象就可以明显看出来:

       可以得出结论一: 继承过来的成员变量 m_type(4个字节) + _vfptr(4个字节) =  8个字节。        


         

        继续探索虚函数表的原理, 创建以下子类对象并通过父类指针指向子类对象调用speak函数发生多态:

int main(){

	ChinesePer chs;
	ChinesePer chs2;
	EnglishPer eng;

    Person *ptr = &chs;		//父类指针指向子类对象
	Person *ptr1 = &chs2;
	Person *ptr2 = &eng;

	ptr->speak();
	ptr1->speak();
	ptr2->speak();
}

     以上代码执行后会发生多态:

          此时我们看看三个对象的内存分布:

        用图片简要描述一下就是:

         在这里可以先得到结论二: 同一个子类的所有对象共享一个虚函数表,指向虚函数表的指针_vptr是相同的。

        

        在内存分布上查看一下 eng对象的虚函数指针地址情况:

         可以看到该虚函数指针的地址上的值,存放的正是 该子类中的重写函数 speak()函数的地址。

        如果把这个地址的值,修改为 Chineseper 类中的重写函数speak() 的地址值,会发生什么?

         手动修改了eng对象中虚函数指针内的地址值,将改值本来是存放的是 EnglishPer 类中的speak() 函数的地址,现在更改为 ChinesePer 类中speak() 函数的地址。

        单步走发生多态:

        至此可以得出结论三:

        当基类函数加了virtual 关键字后,虚函数的调用方法是间接调用:先查虚函数表的地址(也就是指向虚函数表的指针 _vptr),再查虚函数表中的虚函数指针。

        

        不妨在基类继续添加两个虚函数

class Person
{
public:
	virtual void speak() {
		cout << "说人话" << endl;
	}

	virtual void eat() {
		cout << "吃饭" << endl;
	}

	virtual void sleep() {
		cout << "睡觉" << endl;
	}

private:
	int m_type =1 ;
};

        子类只重写了speak函数,查看一下chs对象的虚函数指针地址存放的值:

         的确存放的还是各个函数的地址,且是连续存放的,因此在进行查表调用虚函数的时候,也是每移动4个字节指向的就是一个函数的指针地址。

        可以简要描述一下形式就很直观了:


 

总结:

        1.增加了virtual 关键字的对象头部4个字节是一个指针,指向了虚函数表的地址(单继承情况下)。

        2. 同一个子类的所有对象共享一个虚函数表,指向虚函数表的指针_vptr是相同的。

        3. 当基类函数加了virtual 关键字后,虚函数的调用方法是间接调用:先查虚函数表的地址(也就是指向虚函数表的指针 _vptr),再查虚函数表中的虚函数指针。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值