C ++如何选择要调用的重载函数?

时间:2008-12-22 04:26:40

标签: c++ inheritance programming-languages function multiple-inheritance

说我有三个班级:

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

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

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

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

我用这两个实例调用此函数:

doIt(new Both());

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

除了这一个,C ++编译器判定调用是不明确的并且抛出错误(如果有的话)的情况是什么?编译器如何确定这些情况是什么?

6 个答案:

答案 0 :(得分:7)

简单:如果它不明确,那么编译器会给你一个错误,迫使你选择。在你的代码段中,你会得到一个不同的错误,因为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;

答案 1 :(得分: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)

答案 2 :(得分:3)

这是使用boost::implicit_cast

的完美示例
void doIt(X *arg) { }
void doIt(Y *arg) { }

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

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

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

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

答案 3 :(得分:2)

编译器执行深度搜索,而不是选择过载的广度搜索。 完整答案在Herb Sutter's exceptional C++,遗憾的是我手边没有这本书。

编辑:现在手头拿着这本书 它被称为深度优先规则称为"The Interface Principle"

  

接口原则对于X类,   所有功能,包括免费   功能,即(a)“提及”   X和(b)“供给”X.   在逻辑上是X的一部分,因为它们   形成X界面的一部分。

但是有一个名为"Koenig Lookup"的辅助规则,这会让事情变得更难。

  

引用:“(简化):如果你提供一个   类类型的函数参数(这里   x,类型A :: X),然后查找   正确的函数名称编译器   考虑匹配名称   命名空间(此处为A)包含   参数的类型“ -Herb Sutter,   特殊的C ++,p120

答案 4 :(得分:1)

您需要将您的参数显式地转换为x或y

doIt(new Both());

所以添加......

(X *)或(Y *)

像...

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

答案 5 :(得分:0)

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

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