如何重载和覆盖一起工作?

时间:2013-03-03 00:53:21

标签: c++ polymorphism overloading override dynamic-binding

我理解重载和覆盖的基础知识 - 但有些事让我感到困惑。我将尝试使用一个简单的例子来解释:

  • B类具有功能X(B& b)
  • D类继承自B类。
  • D类用X(B& b)覆盖X,并用X(D& d)重载它。

然后我有以下代码:

void test(D& d1, B& b1, D& d2, B& b2){
    d1.X(d2);
    d1.X(b2);
    b1.X(d2);
    b1.X(b2);
}

int main(){
    D d1, d2, d3, d4;
    test(d1, d2, d3, d4);
}

我非常不确定test()的第三行和第四行将如何确定调用哪个X()实现以及正在发生的一般机制。

2 个答案:

答案 0 :(得分:2)

您在X中声明虚拟函数B(B::X),并覆盖派生类X中的D(D::X)。如果B::XD::X的参数列表不同,则B::XD::X被视为不同,D::X不会覆盖B::X,{ {1}}不是虚拟的(除非您使用virtual关键字声明它)。相反,D::X隐藏D::X

B::X

您甚至无法致电#include <iostream> using namespace std; struct B { virtual void X() { cout << "Class B" << endl; } }; struct D: B { void X(int) { cout << "Class D" << endl; } }; int main() { D d; B* pb = &d; // d.X(); pb->X(); } ,它会被d.X()隐藏。但D::X(int)没问题。

所以在你的情况下:

pb->X()

struct B { virtual void X(B& b) { cout << "Class B" << endl; } }; struct D: B { void X(B& b) { cout << "Class D" << endl; } void X(D& d) { cout << "Class D" << endl; } }; 会隐藏D::X。因此B::X中的d1.X(d2)d1.X(b2)test()无关。 B::X中的b1.X(d2)b1.X(b2)会调用test()。尽管D::X在D中不可见,但B::X是虚拟的,无论您是否使用virtual关键字声明D::X(B&)。编译器知道它是一个虚函数,因此调用D::X(B&)

编辑:关于b1.X(b2)的更多解释,B :: X是一个虚函数,D :: X覆盖它,所以它肯定会通过动态绑定调用D :: X.并且在编译时确定重载,因此它不会调用D :: X(D&amp;)。

答案 1 :(得分:1)

涉及两个步骤:重载选择(X(B&)X(D&)),一旦完成,找到所选功能的正确实现。前者发生在编译时,取决于对象静态类型其参数,后者发生在运行时并依赖于动态类型<对象的/ em>(注意它取决于参数的动态类型)。

这四个对象声明如下:d1d2D&,因此他们的静态类型D&,{{ 1}}和b1声明为b2,因此其静态类型为B&。静态类型是您在代码中声明的内容。

但是所有四个动态类型都是B&,因为所有四个引用实际上都是指您创建为D的对象-D中的对象。

因此,第一步,重载选择:对于main()b1.X(b2),只有一个可能的重载b1.X(d2),因为静态类型为X(B&)B&的类定义只有这一个函数。但在Bd1.X(b2)的情况下,重载选择基于d1.X(d2)的类定义,因为静态类型为D。因此,需要考虑两个重载:D&X(B&)。当参数为X(D&)时,选择前一个重载,当参数为b2时,选择后一个重载 - 所有这些都基于静态(=声明的)对象和参数类型。

第二步,选择所选重载的正确实现。这在运行时发生,取决于对象的动态类型(而不是参数)。因此,对于d2,由于b1.X(b2)的动态类型为b1,因此最终会调用DD::X(B&)也是如此:上一步中选择的重载是b1.X(d2),但所选的实现是X(B&)。 (D::X(B&)此时不是候选者,因为这将是一个不同的重载,并且已经根据静态类型选择了重载。对于D::X(D&)d1.X(b2),所选函数与第一步d1.X(d2)D::X(B&)中的相同,因为对象的动态类型相同作为静态类型。