class A
{
public:
virtual void msg() { std::cout << "msg in A" << std::endl; }
};class B : public A
{
public:
   B::B() { msg(); }  // &Ocirc;&Uacute;&sup1;&sup1;&Ocirc;ì&Ouml;&ETH;&micro;÷&Oacute;&Atilde;msg()·&frac12;·¨
   void callmsg() { msg(); }
};class C : public B
{
virtual void msg() { std::cout << "msg in C" << std::endl; }
};
   
int main() {
    C *c = new C;
    c->callmsg();    delete c; c = NULL;
    system("pause");    return 0;
}//////////////////////////////////////////////////////////////////////////////////
输出结果:
msg in A
msg in C我不知道怎么比较合理正规的解释这个问题?
谢谢各位帮助

解决方案 »

  1.   

    为什么后者是调用C,而前者却调用A中的msgBTW:上面//后的乱码不影响的,因为是中文的注释
      

  2.   

    这个当然,因为是在B的构造函数里面嘛……对于有继承的情况,构造函数还要干一些见不得人的事情,譬如修改虚表什么的(虚拟继承更麻烦,还要根据编译器实现来看……shit),而B之前只有一个A::msg,如此的话,B的构造函数自然只能看到这一个……但是到了B的成员函数里面,由于C的构造函数已经调用完毕了,C的构造函数完成了修改虚表里面msg的指向,所以msg这个位置已经是填入了C::msg的指针了,所以调用的话就变成了调用C::msg了……
      

  3.   

    那怎么才能在初始化中得到msg in C
    我翻了下inside c++ object model也没找到答案
      

  4.   

    可以这样理解:
    对于构造函数,自然是要先构造基类对象,然后再逐步构造子类对象。因此,在C *c = new C;时,首先会构造A对象部分,然后构造B对象部分,在构造A对象部分时,虚函数msg已经形成。构造B对象部分时,会调用msg函数,由于此时C对象还没有开始构造,因此,虚拟机制是无法找到C对象的msg函数的,因此,它必然就执行A对象中的msg函数了。因此输出为msg in A
    但是,当C *c = new C执行完毕后,C对象部分也已经构造完成,这时候调用c->callmsg();由于C对象构造完成,因此虚拟机制自然就能够定位到C对象的msg函数了,因此输出为msg in C
    不知道这样解释是不是可以。
      

  5.   

    no no no,楼上说错,还是会使用到虚表……有例为证……
    #include <iostream>
    using namespace std;
    struct A
    {
    virtual void func()
    {cout<<"a";}
    };struct B:A
    {
    void func()
    {
    cout<<"b";
    }
    };struct C:B
    {
    C()
    {
    func();
    }
    };int main()
    {
    C wokao;
    }
      

  6.   

    上面输出的是b,而不是a,足以证明有多态的存在……(好歹C++ Primer我也看了一遍,如果构造函数里面没有多态的话我不会不知道的……)
    =======================================================回复人: 84830388(新手上路) ( ) 信誉:106  2005-07-15 12:46:00  得分: 0  
     
     
       可以这样理解:
    对于构造函数,自然是要先构造基类对象,然后再逐步构造子类对象。因此,在C *c = new C;时,首先会构造A对象部分,然后构造B对象部分,在构造A对象部分时,虚函数msg已经形成。构造B对象部分时,会调用msg函数,由于此时C对象还没有开始构造,因此,虚拟机制是无法找到C对象的msg函数的,因此,它必然就执行A对象中的msg函数了。因此输出为msg in A
    但是,当C *c = new C执行完毕后,C对象部分也已经构造完成,这时候调用c->callmsg();由于C对象构造完成,因此虚拟机制自然就能够定位到C对象的msg函数了,因此输出为msg in C
    不知道这样解释是不是可以。
      
     
    =====================================================
    msg形成在代码写完的时候就完成了,构造函数只不过是写vtbl而已,把msg的位置写进去而以……
      

  7.   

    可以这样理解 virtual【虚】函数  共用一个地址如果被重载了,那么只有重载的这个有效,父类的无效了!再看看上边结果是不是很好理解了
      

  8.   

    我觉得84830388(新手上路)说的差不多了,只不过不严密而已。 修改下:对于构造函数,自然是要先构造基类对象,然后再逐步构造子类对象。
    因此,在C *c = new C;时,首先会构造A对象部分,然后构造B对象部分,最后C部分。
    在构造A对象部分时,虚表里msg的地址是A::msg。
    在构造B对象部分时,虚表里msg的地址是A::msg。(构造函数调用msg函数是A::msg)
    在构造C对象部分时,虚表里msg的地址是C::msg。
    但是,当C *c = new C执行完毕后,C对象部分也已经构造完成,
    这时候调用c->callmsg();是C::msg不知道这样解释是不是可以。
      

  9.   

    那怎么才能在初始化中得到msg in C
    ---------------
    这个我想可以在C::C里调用msg,别的想不出来:(
      

  10.   

    重写c的ctor?
    这句太牛了吧,什么意思?
      

  11.   

    重写C类的constructor(构造函数),如果我没猜错的话
      

  12.   

    他的意思是叫你在C::C里面静态调用C::msg……反正在B的ctor里面使用C的msg是不现实的,至少C++特性里面没加上这一条,如果你真的需要的话,只能靠在A的构造函数里面hack虚表了……