在C ++中隐藏,重载或覆盖

王凯文|

然后我又有一个问题。像这样的东西:

#include <iostream>
using namespace std;

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

class Derive:public Base
{
public:
    void foo()
    {
        cout<<"Derive."<<endl;
    }
};

int main()
{
    Derive d;
    Base *pb=&d;    //attention here
    pb->foo();      //ateention here
    system("pause");
    return 0;
}

输出为“ Base”。然后功能规则不起作用,对此我感到困惑,您能帮我吗?谢谢。

杰里·科芬(Jerry Coffin)

由于foo不是虚拟的,因此调用的函数基于静态类型(即,声明指针指向的类型)而不是动态类型(指针当前指向的对象的类型)。

还有一些棘手的情况需要考虑。一点(其他一些答案实际上在某种程度上是令人误解的)是,真正重要的不仅是函数名称,还包括整个函数签名。例如:

#include <iostream>

struct base { 
    virtual void foo() { 
        std::cout << "base::foo";
    }
};

struct derived : base { 
    virtual void foo() const { 
        std::cout << "derived::foo";
    }
};

int main(){ 
    base *b = new derived;

    b->foo();
}

在派生类和派生类中都是foo合格的virtual,但该调用b->foo() 仍会打印出来base::foo

const加入的签名derived::foo意味着它不再的签名相匹配base::foo,所以不是重写虚拟函数,我们还是结束了名称相同的两个单独的功能,所以derived::foobase::foo,但不覆盖它。尽管virtual有条件,我们还是获得了静态绑定,因此b->foo();即使b指向该derived类型的对象,也将调用基本函数而不是派生函数

正如Tony D在评论中指出的那样,C ++ 11为该语言增加了新的皱纹,以帮助确保避免这种情况的发生。当您想覆盖基类函数时,可以将标识符添加override到派生类的函数中:

struct derived : base {
     virtual void foo() const override {
         std::cout << "derived::foo";
     }
};

这样,如果函数签名有所不同(如此处所示的情况),则编译器将生成一条错误消息,警告您derived::foo标记为的事实override,但实际上并未从基类中覆盖函数。但是,这是在C ++ 11中添加的,因此,如果您使用的是较旧的编译器,则可能无法实现此功能(尽管值得庆幸的是,未实现此功能的编译器很快就淡出了人们的视线)。

将基类中的签名更正为:

virtual void foo() const // ...

...将让代码进行编译,并产生正确的结果。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章