说我有三个班级:
class X{};
class Y{};
class Both : public X, public Y {};
我的意思是说我有两个类,然后是第三个类,它们都扩展了(多重继承)。
现在说我在另一个类中定义了一个函数:
void doIt(X *arg) { }
void doIt(Y *arg) { }
我用这两个实例调用此函数:
doIt(new Both());
这会导致编译时错误,表明函数调用不明确。
除了这一个,C ++编译器判定调用是不明确的并且抛出错误(如果有的话)的情况是什么?编译器如何确定这些情况是什么?
答案 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 ++编译器将始终选择它在编译时可以确定的最接近和最具体的匹配。
但是,如果您的对象来自两者,我认为编译器应该给您一个错误或至少一个非常严重的警告。声明顺序无关紧要,因为这是关于子类型关系的,第一个对象不是“更多的子类型”而不是另一个。