[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:

 

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
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
}

 

 

 

 

转载于:https://www.cnblogs.com/aoaoblogs/archive/2010/09/07/1820964.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值