Cpp 对象模型探索 / 静态联编和动态联编

一、源码

#include <iostream>

class Father
{
public:
	Father()
	{
		/**
		 * 该处直接将该对象清零,意味着虚函数表指针亦被清零。
		 */
		memset(this, 0, sizeof(Father));
	}
public:
	virtual void Func1()
	{
		std::cout << "Fahter::Func1()" << std::endl;
	}
	virtual void Func2()
	{
		std::cout << "Fahter::Func2()" << std::endl;
	}
	virtual void Func3()
	{
		std::cout << "Fahter::Func3()" << std::endl;
	}
};

int main()
{
	Father father;

	father.Func1();
	father.Func2();
	father.Func3();

	Father* pfather = new  Father();
	
	/**
	 * 此处开始崩溃,因为虚函数表指针已经被清零。
	 */
	pfather->Func1();
	pfather->Func2();
	pfather->Func3();
	return 0;
}

结果

二、分析

问题,为什么含有虚函数的类,若是直接申请为实例对象,可以调用虚函数,但是通过指针 new 出的实例却崩溃呢?

原因,这里有个静态联编和动态联编的概念。

       静态联编的意思是在编译期间就能确定调用的函数的地址,即:call (地址),地址是确定的值。

       动态联编的意思是在运行期间才能确定调用的函数的地址。方法是通过对象的虚函数表指针找到虚函数表,再通过虚函数表找到虚函数,这也是多态的实现机理。而多态的实现,只针对指针或者引用。

       上述代码中,因为对象“father”不是指针或者引用,所以尽管存在虚函数,但是这些虚函数在不用在多态的情况下,其功能和普通函数是一样的,所以编译器直接将其按照静态编译来处理。

       针对上述代码中的"pfather",因为是 new 出的对象,所以编译器要考虑下面多态的可能性,所以调用虚函数是按照动态联编的调用顺序来调用的,即:虚函数表指针 --> 虚函数表 --> 虚函数 。但是,问题出在了“Father”类的构造函数中,因为该构造函数初始化对象的方法是直接将整个对象都初始化为0,这里面也包括虚函数表指针,所以,走多态的路来调用虚函数直接 Over 了。。所以上述通过 pfather 调用虚函数的方法就产生了崩溃。

 

(SAW:Game Over!)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值