C4250警告产生的原因及解决方法

使用MSVC编译以下代码会产生C4250警告:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>

class A {
public:
virtual void Print() {
std::cout << "A::Print" << std::endl;
}
};

class B : virtual public A {

};

class C : virtual public A {
public:
void Print() override {
std::cout << "C::Print" << std::endl;
}
};

class D : public B, public C {

};

int main() {

D d;
d.Print();
}

警告信息为warning C4250: “D”: 通过域控制继承“C::C::Print”。这样的警告信息并没有什么价值,我们需要自己来分析一下。

上述代码塑造出了菱形继承关系,如下所示:

根基类A定义了一个虚方法Print,因此在子类B和C中存在继承而来的Print,其中C重写了该方法。D多重继承于B和C,因此它会同时继承B和C的Print。这时问题来了,当对D的实例调用Print时,它应该调用B::Print还是C::Print呢?这里编译器做出了选择,它调用的是在基类中被重写的版本,也就是C::Print。然而,这很有可能不是我们想要的结果,所以编译器发出警告,提醒我们这里可能存在问题。

假如B也重写了Print,会怎么样呢?在这种情况下编译会失败,因为两个基类都重写了Print,编译器无法做出选择。

解决的方法很简单,只要在D中也重写Print即可,这样可以明确地告诉编译器,我们要调用的就是D::Print,从而消除了编译器的疑虑。在实现D::Print的时候,可能需要调用基类版本,这时要根据具体情况来决定调用哪个版本。