然后我又有一个问题。像这样的东西:
#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”。然后功能规则不起作用,对此我感到困惑,您能帮我吗?谢谢。
由于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::foo
皮base::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] 删除。
我来说两句