[C++]Call virtual member function in constructor or destructor

嗷嗷按,今天被问到在constructor/destructor中调用virtual member function的问题。答错了,很羞耻。

依稀记得在constructor/destructor调用virtual member function不好,就随口答道不能调用,可能会出错。

后来仔细想想不对,羞耻呀。调用是可以的,从语言角度没错,只不过和其他情况下调用虚函数有些不同。

看代码:

 

  
    
class A
{
public :
A()
{
printf(
" \n\nclass A this = %x, *this = %x\n " , this , * ( int * )( this ));
ff();
gg(
this );
}
void gg(A * p)
{
printf(
" p = %x this = %x, *this = %x\n " ,p, this , * ( int * )( this ));
p
-> ff();
}
virtual void ff()
{
printf(
" A::ff()\n " );
}
};
class B: public A
{
public :
B()
{
printf(
" \n\nclass B this = %x, *this = %x\n " , this , * ( int * )( this ));
ff();
gg(
this );
}
virtual void ff()
{
printf(
" B::ff()\n " );
}
};
class C: public B
{
public :
C()
{
printf(
" \n\nclass A this = %x, *this = %x\n " , this , * ( int * )( this ));
ff();
gg(
this );
}
virtual void ff()
{
printf(
" C::ff()\n " );
}

};

int main(){
C c;
}

 

其输出是

class A this = 12ff60, *this = 4091ac

A::ff()

p = 12ff60 this = 12ff60, *this = 4091ac

A::ff()

 

class B this = 12ff60, *this = 4091b8

B::ff()

p = 12ff60 this = 12ff60, *this = 4091b8

B::ff()

class A this = 12ff60, *this = 4091c4

C::ff()

p = 12ff60 this = 12ff60, *this = 4091c4

C::ff()

 

三次在构造函数中调到函数ff(), 其指向的都是base类的函数,而不是派生类的函数。

对于直接在构造函数调用的ff(),比如:

 

  
    
A()
{
printf(
" \n\nclass A this = %x, *this = %x\n " , this , * ( int * )( this ));
ff();
gg(
this );
}

 

实际上这里ff()生成的代码是一个静态的call, 类似call 0x123456

 

对于在其他函数中调用的ff()比如

 

  
    
void gg(A * p)
{
printf(
" p = %x this = %x, *this = %x\n " ,p, this , * ( int * )( this ));
p
-> ff();
}

 

p->ff()和其他情况下生成的代码都一样,都是 call [*this + 0],call到的还是虚函数表。

 

奥妙就在于在构造的过程中,调用base类的构造函数时,虚函数表的入口地址(*this)是变化的。

 

当然,标准中没有规定怎么实现,具体的描述如下

Member functions, including virtual functions (10.3), can be called during construction or destruction(12.6.2). When a virtual function is called directly or indirectly from a constructor (including from themem-initializer for a data member) or from a destructor, and the object to which the call applies is theobject under construction or destruction, the function called is the one defined in the constructor ordestructor’s own class or in one of its bases, but not a function overriding it in a class derived from the constructoror destructor’s class, or overriding it in one of the other base classes of the most derived object(1.8). If the virtual function call uses an explicit class member access (5.2.5) and the object-expressionrefers to the object under construction or destruction but its type is neither the constructor or destructor’sown class or one of its bases, the result of the call is undefined.

Example:

 

代码
   
     
class V {
public :
virtual void f();
virtual void g();
};
class A : public virtual V {
public :
virtual void f();
};
class B : public virtual V {
public :
virtual void g();
B(V
* , A * );
};
class D : public A, B {
public :
virtual void f();
virtual void g();
D() : B((A
* ) this , this ) { }
};
B::B(V
* v, A * a) {
f();
// calls V::f, not A::f
g(); // calls B::g, not D::g
v -> g(); // v is base of B, the call is well-defined, calls B::g
a -> f(); // undefined behavior, a’s type not a base of B
}

 

 

 

 

你可能感兴趣的:(Constructor)