以下代码
#include <iostream>
using namespace std;
class A {};
class B : public A {};
class C : public B {};
void foo(A *a) {
cout << 'A' << endl;
}
void foo(B *b) {
cout << 'B' << endl;
}
int main() {
C *c = new C[10];
foo(c);
}
编辑精美并打印&#39; B&#39;如预期的那样。
但是当我将main()
功能更改为
int main() {
C c[10];
foo(c);
}
我收到编译错误
test_arr.cpp: In function 'int main()':
test_arr.cpp:23:10: error: call of overloaded 'foo(C [10])' is ambiguous
test_arr.cpp:23:10: note: candidates are:
test_arr.cpp:11:6: note: void foo(A*)
test_arr.cpp:15:6: note: void foo(B*)
为什么现在模棱两可?我认为阵列总是只是一个指针,所以我不能真正看到差异。
修改:
我刚刚意识到我发布的所有代码都是一个坏主意:只要您将数据成员添加到类中并在foo
函数中访问它们,就会遇到问题,如{{ 3}},因为foo(B*)
函数无法知道它实际上正在处理可能需要更多内存空间的C
个对象。所以不要这样做!
尽管如此,我仍然有兴趣理解为什么编译器会在这里抱怨歧义,因为我真的没有在这里看到 的问题。
答案 0 :(得分:5)
我相信这是一个gcc bug。代码编译在clang上。
首先,两位候选人都是可行的。来自[conv]:
标准转换序列是一系列标准转换,顺序如下:
- 来自以下集合的零或一次转换:左值到右值转换,数组到指针转换, 和功能到指针的转换 - 来自以下集合的零或一次转换:整数促销,浮点促销,积分 转换,浮点转换,浮点积分转换,指针转换,指针指向 成员转换和布尔转换。
对foo
的两次调用都涉及数组到指针的转换(从C[10]
到C*
),然后是指针转换(从C*
到A*
1}}或B*
)。这是允许的标准转换。
现在,我们如何对这些转化进行排名?有趣的是,标准中的行匹配完全我们的用例,在[over.ics.rank]中:
具有相同等级的两个转换序列 除非符合以下规则之一,否则无法区分:
- 如果B类直接或间接地从A类派生而C类是直接或间接派生的 B,
- 将C *转换为B *优于将C *转换为A *
我们有两个相同等级(转换)的转换序列,它们都是可行的,但一个被认为比另一个更好。代码应明确地优先于foo(B* )
而不是foo(A* )
。 c
被声明为数组的事实不应该使它变得模棱两可。
答案 1 :(得分:1)
C c[10]
不是多态类型。您可能能够获得指向数组中第一个项目的指针,但这仍然只是C
。
如果您尝试将其强制转换为B
,则会进行切片。
C* c = new C();
可以是dynamic_cast
到B
。