参见【深入探索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设定可以省略。