• 虚函数与const

    Const这个关键字放在不同的地方将起到不同的作用。

    题目是这样的:

    class XBase

    {

    public:

    virtual void play()const

    {

    cout<<"base play"< }

    };

    class XWind:public XBase

    {

    public:

    void play()

    {

    cout<<"wind play"< }

    };

    class XBrass:public XWind

    {

    public:

    void play()

    {

    cout<<"brass play"< }

    };

    void Tune(XBase& b)

    {

    b.play();

    }

    void main()

    {

    XBase* base[] = {new XWind(),new XBrass()};

    for(int i = 0;i < 2;i++)
    {

    Tune(*base[i]);

    }

    }

    问这段代码的运行结果:

    开始我以为很容易:

    不就是:

    wind play

    brass play

    回来我运行一遍,发现错了:

    base play

    base play

    但是把基类改为:

    class XBase

    {

    public:

    const virtual void play()

    {

    cout<<"base play"< }

    };

    派生类作相应的改动:

    class XWind:public XBase

    {

    public:

    const void play()

    {

    cout<<"wind play"< }

    };

    class XBrass:public XWind

    {

    public:

    const void play()

    {

    cout<<"brass play"< }

    };

    则运行结果为:

    wind play

    brass play

    原来Const这个关键字放在不同的地方将起到不同的作用。

    大家可以试一下,顺便说一下原理。

    解答者:

    不论派生类如何修改只要与基类不符就选择调用基类

    class XBase

    virtual void play()const; // 原型:void play() cont

    class XWind:public XBase // 从XBase派生

    void play(); // 不符合基函数play,调用基play

    XBrass:public XWind // 从XWind派生

    void play(); // 符合函数XWind::play,但因为

    // XWind::play调用XBase::play

    // 因此XBrass::play调用XBase::play

    你可以试试这样修改,你就会明白

    XBase

    virtual void play() const;// 原型

    XWind : public XBase

    void play() cont; // 符合,调用自己的play

    XBrass : public XWind

    void play(); // 与XWind::play不符,调用XWind::play

    ---------------------------------------------------------------

    XBase

    virtual void play() const;// 原型

    XWind : public XBase

    void play(); // 不符合,调用XBase::play

    XBrass : public XWind

    void play() const; // 与XWind::play不符,往下一级寻找play

    // 与XBase::play相同,调用自己的play

    ----------------------------

    两次的输出结果为:

    1.wind play

    wind play

    2.base play

    brass play

    解答者说的是正确的。 不过具体原因,自己写个c++例子,查它的汇编代码就明白了。

    比如 XBase 的虚函数表里有一个函数指针:

    _XBase_play

    XWind的虚函数表里有两项:

    _XBase_play

    _XWind_play如果通过XBasePtr->play来调用,编译器是按虚函数表里的偏移量来call的,这时候会调用到base的play函数。

    如果通过XWindPtr->play来调用,会调用到XWind的play函数。

    如果const修饰一致,那么XWind的虚函数表里将只有一项:

    _XWind_play

    这个问题反应了c++一个比较搞笑的情况:编译器是尽量防止对只在派生类中存在的函数做虚函数调用的,但是

    这里显然突破了这种限制。还有一个例外的地方是明确指出指针在运行时是指向哪个子对象。
    2010/11/5 11:04:02
举报不良信息

 

 大  小