我理解重载和覆盖的基础知识 - 但有些事让我感到困惑。我将尝试使用一个简单的例子来解释:
然后我有以下代码:
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()实现以及正在发生的一般机制。
答案 0 :(得分:2)
您在X
中声明虚拟函数B(B::X)
,并覆盖派生类X
中的D(D::X)
。如果B::X
和D::X
的参数列表不同,则B::X
和D::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&)
。
答案 1 :(得分:1)
涉及两个步骤:重载选择(X(B&)
与X(D&)
),一旦完成,找到所选功能的正确实现。前者发生在编译时,取决于对象的静态类型和其参数,后者发生在运行时并依赖于动态类型<对象的/ em>(注意它不取决于参数的动态类型)。
这四个对象声明如下:d1
和d2
是D&
,因此他们的静态类型是D&
,{{ 1}}和b1
声明为b2
,因此其静态类型为B&
。静态类型是您在代码中声明的内容。
但是所有四个动态类型都是B&
,因为所有四个引用实际上都是指您创建为D
的对象-D
中的对象。
因此,第一步,重载选择:对于main()
和b1.X(b2)
,只有一个可能的重载b1.X(d2)
,因为静态类型为X(B&)
,B&
的类定义只有这一个函数。但在B
和d1.X(b2)
的情况下,重载选择基于d1.X(d2)
的类定义,因为静态类型为D
。因此,需要考虑两个重载:D&
和X(B&)
。当参数为X(D&)
时,选择前一个重载,当参数为b2
时,选择后一个重载 - 所有这些都基于静态(=声明的)对象和参数类型。
第二步,选择所选重载的正确实现。这在运行时发生,取决于对象的动态类型(而不是参数)。因此,对于d2
,由于b1.X(b2)
的动态类型为b1
,因此最终会调用D
。 D::X(B&)
也是如此:上一步中选择的重载是b1.X(d2)
,但所选的实现是X(B&)
。 (D::X(B&)
此时不是候选者,因为这将是一个不同的重载,并且已经根据静态类型选择了重载。对于D::X(D&)
和d1.X(b2)
,所选函数与第一步d1.X(d2)
和D::X(B&)
中的相同,因为对象的动态类型相同作为静态类型。