您的 B 类不会覆盖 A 中的成员函数,它会重载它。或者无论如何都要尝试,稍后再看看关于隐藏的内容。
重写是指派生类从基类定义自己的虚拟成员函数版本。重载是当您定义具有相同名称的不同函数时。
当对具有基类类型的指针或引用进行虚拟调用时,它只会“考虑”派生类中的覆盖,而不是重载。这是必不可少的 - 对于调用者处理 B 的实例,就好像它做了 A 可以做的所有事情(这是动态多态性和虚函数的重点),它的 hello 函数需要能够接受任何对象A 类型。hello 函数只接受 B 类型的对象,而不是任何 A,限制性更强。不能起到A的hello函数的作用,所以不是override。
如果您尝试在 A 和 B 上调用 hello 并传递 A 或 B 类型的对象,您应该能够看到差异。 A 有一个接受 A 的函数(你没有定义它,所以如果你调用它,那么你的程序将无法链接,但你可以修复它)。 B 有一个采用 B 的函数。它们恰好具有相同的名称,当然,由于 B 派生自 A,因此您可以将 B 传递给采用 A 的函数。但是 B 的函数在虚拟调用中不充当覆盖.
可以在 B 对象上调用 A 的函数,但只能通过指向 A 的引用或指针。C++ 的一个特点是 B 中 hello 的定义隐藏了 A 中的定义。如果重载是你的想要,可以通过将using A::hello; 添加到 B 类来取消隐藏基类函数。如果您想要覆盖,则必须定义一个采用相同参数的函数。例如:
#include <iostream>
class A
{
public:
virtual int hello(A a) {std::cout << "A\n"; }
virtual int foo(int i) { std::cout << "A::Foo " << i << "\n"; }
};
class B : public A
{
public:
using A::hello;
// here's an overload
int hello(B b){ std::cout << "B\n"; };
// here's an override:
virtual int foo(int i) { std::cout << "B::Foo " << i << "\n"; }
};
int main() {
A a;
B b;
a.hello(a); // calls the function exactly as defined in A
a.hello(b); // B "is an" A, so this is allowed and slices the parameter
b.hello(a); // OK, but only because of `using`
b.hello(b); // calls the function exactly as defined in B
A &ab = b; // a reference to a B object, but as an A
ab.hello(a); // calls the function in A
ab.hello(b); // *also* calls the function in A, proving B has not overridden it
a.foo(1); // calls the function in A
b.foo(2); // calls the function in B
ab.foo(3); // calls the function in B, because it is overridden
}
输出:
A
A
A
B
A
A
A::Foo 1
B::Foo 2
B::Foo 3
如果从B中去掉using A::hello;这一行,那么调用b.hello(a);编译失败:
error: no matching function for call to `B::hello(A&)'
note: candidates are: int B::hello(B)