编译器在构造函数里都做了些什么?

  我们都知道,C++是一种面向对象的语言,其中一个重要特性是多态性。多态性是通过基类指针指向子类对象,并通过这个基类指针调用子类函数(虚函数)来实现的。但是,看下面这个例子,我可以通过在构造函数里增加一行代码,从而使得这个多态不起作用!

  看下面例子:

class Base
{
public:
    Base()
    {
        cout<<"Base::Base()"<<endl;
    }

    virtual ~Base()
    {
        cout<<"Base::~Base()"<<endl;
    }

    virtual void print()
    {
        cout<<"Base::print()"<<endl;
    }
};


class Derived: public Base
{
public:
    Derived()
    {
        //memcpy(this, 0, sizeof(Derived));
        cout<<"Derived::Derived()"<<endl;
        memset(this, 0, sizeof(Derived));
    }

    ~Derived()
    {
        cout<<"Derived::~Derived()"<<endl;
    }

    void print()
    {
        cout<<"Derived::print()"<<endl;
    }
};



int main()
{
    Base *b = new Derived();
    b->print();
    return 0;
}

  如果按照C++的多态特性,它应该输出:Derived::print(),但是真是如此吗?

  下面,我们编译,运行,看看输出什么东西:

$ ./nopoly 
Base::Base()
Derived::Derived()
Segmentation fault (core dumped)

  令人大跌眼镜,居然段错误!什么也没能输出,是什么原因导致的呢?其实是因为这么一行代码:

memset(this, 0, sizeof(Derived));

  我们将vpt清为零了,因此,找不到Deried类的print函数,因此,便出现段错误了。

 

  那么,我们回想一下,编译器到底在我们的构造函数里都干了些什么。

1. 记录在 member initialization list 中的 data members 初始化操作会被放进构造函数本身,并以members声明的顺序进行初始化;

2. 如果有一个member并没有出现在member initialization list 中,但它有一个default constructor,那么,该default constructor 必须被调用;

3. 在那之前,如果class object有virtual table pointer(s),它(们)必须被设定初值,并指向适当的virtual table(s)。

4. 在那之前,所有上一层的 base class constructors 必须被调用,并以base class 的声明顺序为次序(与member initialization list 中的顺序没有关联):

  如果base class 被列于member initialization list中,那么任何明确指定的参数都应该传递过去;

  如果base class 没有被列于 member initialization list 中,而它有default constructor (或default memberwise copy constructor ),那么就调用之。

  如果base class 是多重继承下的第二或后继的base class ,那么this 指针必须有所调整。

5. 在那之前,所有 virtual base class constructors 必须被调用,从左到右,从最深到最浅:

  如果class 被列于member initialization list 中,那么如果有任何明确指定的参数,都应该传递过去。若没有列于list 中,而class 有一个default constructor,也应该调用之。

  此外,class 中的每一个virtual base class subobejct 的偏移量必须在执行期可被存取;

  如果class object 是最底层的 class,其constructors 可能被调用;某些用以支持这个行为的机制必须被放进来。

 

posted @ 2014-12-17 10:05  wiessharling  阅读(349)  评论(0编辑  收藏  举报