5

假设我有三个课程:

class X{};
class Y{};
class Both : public X, public Y {};

我的意思是说我有两个类,然后是第三个类,它扩展了两者(多重继承)。

现在说我在另一个类中定义了一个函数:

void doIt(X *arg) { }
void doIt(Y *arg) { }

我用两者的实例调用这个函数:

doIt(new Both());

这会导致编译时错误,说明函数调用不明确。

除了这种情况,C++ 编译器在哪些情况下判断调用不明确并抛出错误(如果有)?编译器如何确定这些情况是什么?

4

6 回答 6

8

很简单:如果它不明确,那么编译器会给你一个错误,迫使你做出选择。在您的代码段中,您将得到一个不同的错误,因为 of 的类型new Both()是指向 的指针Both,而两个重载都doIt()按值接受其参数(即它们不接受指针)。如果您更改doIt()为分别采用类型X*和参数Y*,编译器会给您一个关于模棱两可的函数调用的错误。

如果要显式调用其中一个,请适当地转换参数:

void doIt(X *arg) { }
void doIt(Y *arg) { }
Both *both = new Both;
doIt((X*)both);  // calls doIt(X*)
doIt((Y*)both);  // calls doIt(Y*)
delete both;
于 2008-12-22T04:33:36.507 回答
5

我用 gcc 得到这个错误:

jeremy@jeremy-desktop:~/Desktop$ g++ -o test test.cpp
test.cpp: In function ‘int main(int, char**)’:
test.cpp:18: error: call of overloaded ‘doIt(Both&)’ is ambiguous
test.cpp:7: note: candidates are: void doIt(X)
test.cpp:11: note:                 void doIt(Y)
于 2008-12-22T04:32:37.493 回答
3

这是使用的完美示例boost::implicit_cast

void doIt(X *arg) { }
void doIt(Y *arg) { }

doIt(boost::implicit_cast<X*>(new Both));

与其他解决方案(包括 static_cast)不同,如果无法从Both*to 进行隐式转换,则转换将失败X*。这是通过一个技巧完成的,最好用一个简单的例子来展示:

X * implicit_conversion(X *b) { return b; }

就是这样boost::implicit_cast,只是它是一个告诉它类型的模板b

于 2008-12-27T06:28:15.447 回答
2

编译器进行深度搜索,而不是选择重载的广度搜索。完整的答案在Herb Sutter 出色的 C++中,不幸的是我手头没有这本书。

编辑:现在拿到手头的书它被称为深度优先规则被称为“接口原则”

接口原则 对于类 X,所有函数,包括自由函数,(a)“提及”X 和(b)“提供”X 在逻辑上都是 X 的一部分,因为它们构成 X 的接口的一部分.

但是有一个称为“Koenig Lookup”的次要规则,这使事情变得更加困难。

引用:“(简化):如果你提供一个类类型的函数参数(这里是 x,类型 A::X),那么为了查找正确的函数名,编译器会考虑在包含参数的类型” -Herb Sutter, Exceptional C++, p120

于 2008-12-22T05:48:56.917 回答
1

您需要明确地将您的论点转换为 x 或 y

做(新两者());

所以加...

(X *) 或 (Y *)

像...

doIt((X *)new Both());

于 2008-12-22T05:07:20.947 回答
0

AFAIK C++ 编译器将始终选择它可以在编译时确定的最接近和最具体的匹配。

但是,如果您的对象是从两者派生的,我认为编译器应该给您一个错误或至少一个非常严重的警告。声明顺序应该无关紧要,因为这是关于子类型关系,并且第一个对象不是比另一个对象“更多的子类型”。

于 2008-12-22T04:33:51.030 回答