【深入探索c++对象模型】c++中构造函数调用虚函数的讨论

参见【深入探索c++对象模型】213-219页

    在一个class的constructor中,经由构造中的对象来调用一个virtual function中,其函数实体应该是在此class中有作用的那个,这是由constructors的调用顺序决定的。

#include<string>
#include<iostream>
using namespace std;
class Base
{
public:
	Base(string& s)
	{
		Fuction(s);
	}

	virtual void Fuction(string& s)
	{
		cout << "Base::Fuction" << ' ' << s << endl;
	}
};

class Derived : public Base
{
public:	
	Derived(string& s)
 	{
		Fuction(s);
	}
	virtual void Fuction(string& s)
	{
		cout << "Derived::Fuction" << ' ' << s << endl;
	}
};// 这样定义一个A的对象,会输出什么?

int main()
{
	string str = "Hello";
	Derived a(str);
}
执行结果为
Base::FuctionHello
Derived::FuctionHello
编译器必须保证适当的虚函数实体被调用到,怎么才能实现这一点呢?一般来说可行的方法有三种

a)调用操作必须限制在constructor中直接调用,实现方法是将每一个调用操作以静态方式决议,不要用到虚拟机制实现。
b)在constructor中设置一个标记,然后可以以标记值作为判断依据,产生条件调用操作。
c)根本解决之道是在执行一个constructor是,必须限制一组virtual function候选名单,利用vptr进行设置即可。

下面我们就讨论如何设置vptr以指向正确的vptl?如何初始化vptr?

答:本质上讲这取决于vptr何时被初始化。正确地做法:在base class constructors调用操作之后,但是在程序员的代码或者member initialization list中所列的members初始化操作之前进行。令每一个base class constructor设定对象的vptr,使它指向相关的virtual table之后,构造中的对象就可以严格而正确的变成“构造过程中所幻化出来每一个class”的对象。

接着我们讨论下这样做只能解决没有基类子对象的情况,对于含有基类子对象如何解决?

答:vptr的设置要分两种情况:
a)不含基类子对象的如上所讨论;
b)含有基类子对象的情况的时候,在对base class constructor调用时,其vptr将不再需要对每一个base class constructor中被设定。 
解决之道就是讲constructor分裂为一个完整的object实体和一个subobject实体,在subobject中vptr设定可以省略。

最后回答一下我们标题中的问题:在class的constructor的member initialization list中调用class的虚函数,安全吗?

这和在构造函数内部调用实质是一个问题,初始化列表会被编译器扩展为constructor类代码。就实际而言,将该函数运行于class 中的data member的初始化中,总是安全的。因为此时vptr能保证在member initialization list被扩展之前,由编译器正确设定好。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值