我有以下课程:
class A {
public:
virtual void f() {}
};
class B : public A{
public:
void f(int x) {}
};
如果我说
B *b = new B();
b->f();
编译器说错误C2660:'B :: f':函数不带0个参数。 不应该B中的函数超载它,因为它是一个虚函数?虚拟函数会像这样被隐藏吗?
编辑:我的意思是从A继承B,这显示了相同的行为。
答案 0 :(得分:36)
假设您打算B
派生自A
:
f(int)
和f()
是不同的签名,因此功能不同。
您可以使用具有兼容签名的函数覆盖虚拟函数,这意味着相同的签名,或者返回类型为“更具体”的签名(这是协方差)。
否则,派生类函数会隐藏虚函数,就像派生类声明与基类函数同名的函数一样。您可以将using A::f;
放在B类中取消隐藏名称
或者,您可以将其称为(static_cast<A*>(b))->f();
或b->A::f();
。不同之处在于,如果B
实际上覆盖了f()
,那么前者会调用覆盖,而后者会调用A
中的函数。
答案 1 :(得分:7)
B类不是从A派生的,因此不存在函数F()。你可能意味着:
class A {
public:
virtual void f() {}
};
class B : public A {
public:
void f(int x) {}
};
编辑:我错过了隐藏的实际功能。请参阅Steve Jessop的答案以获得更详尽的解释。
答案 2 :(得分:4)
不,是的,分别。如果您想要重载行为,则需要说
using A::f;
在B。
答案 3 :(得分:2)
B不是从A派生的,正确的声明是:
class B : public A
答案 4 :(得分:2)
当编译器有多种方法来解析符号时,它必须选择哪一个具有优先权,除非代码另有说明。您期望的是超载优先于覆盖。 (over,over,over,aaaaack!对不起,得到了'过来'。)
此示例使B继承了一个虚方法,其中子类提供了重载版本。重载是针对同一类中使用相同方法名但具有不同签名的方法。由于B是A的子类,它重写了f(),这意味着它不能同时成为一个重载。这就是它被隐藏的原因。
对于A类,声明方法
virtual void f() {}
as virtual意味着将使用与您的b声明不一致的某组规则来解析方法。
B *b = new B();
通过创建“b”作为“B”的实例,编译器无需使用“A”中同名方法的虚拟特性。
如果你已经像这样声明了'b'
B *b = new A();
然后调用b-&gt; f();确实会通过使用虚拟分辨率来引用A中的方法。
答案 5 :(得分:2)
在Biern Stroustrup的常见问题解答中,它似乎与答案存在相似的问题:http://www.stroustrup.com/bs_faq2.html#overloadderived
正如他所说:
“在C ++中,范围内没有超载”
但如果你想要
“使用using声明很容易完成”