数组作为指针传递的不明确重载
Ambiguous overload with array passed as pointer
代码如下
#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);
}
编译正常并按预期打印 'B'。
但是当我将 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
函数中访问它们,您将 运行 进入问题,如 here 所述,因为 foo(B*)
函数无法知道它实际上正在处理 C
可能占用更多内存的对象 space。所以不要这样做!
尽管如此,我仍然有兴趣了解为什么编译器在这里抱怨歧义,因为我真的没有看到 that 这里有问题。
C c[10]
不是多态类型。您可能能够获得指向数组中第一项的指针,但那仍然只是一个 C
。
如果您尝试将其转换为 B
,您将得到切片。
C* c = new C();
可以是 dynamic_cast
到 B
.
我认为这是一个 gcc 错误。代码在 clang 上编译。
首先,两位候选人都是可行的。来自 [转化]:
A standard conversion sequence is a sequence of standard conversions in the following order:
— Zero or one conversion from the following set: lvalue-to-rvalue conversion, array-to-pointer conversion,
and function-to-pointer conversion.
— Zero or one conversion from the following set: integral promotions, floating point promotion, integral
conversions, floating point conversions, floating-integral conversions, pointer conversions, pointer to
member conversions, and boolean conversions.
对 foo
的两次调用都涉及数组到指针的转换(从 C[10]
到 C*
),然后是指针转换(从 C*
到A*
或 B*
)。这是允许的标准转换。
现在,我们如何对这些转化进行排名?有趣的是,标准中的行 完全 我们的用例 [over.ics.rank]:
Two conversion sequences with the same rank
are indistinguishable unless one of the following rules applies:
— If class B is derived directly or indirectly from class A and class C is derived directly or indirectly from
B,
— conversion of C* to B* is better than conversion of C* to A*
我们有两个相同等级(Conversion)的转换序列,它们都是可行的,但一个被认为比另一个更好。代码应该明确地更喜欢 foo(B* )
而不是 foo(A* )
。 c
被声明为一个数组这一事实不应该使它变得模棱两可。
代码如下
#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);
}
编译正常并按预期打印 'B'。
但是当我将 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
函数中访问它们,您将 运行 进入问题,如 here 所述,因为 foo(B*)
函数无法知道它实际上正在处理 C
可能占用更多内存的对象 space。所以不要这样做!
尽管如此,我仍然有兴趣了解为什么编译器在这里抱怨歧义,因为我真的没有看到 that 这里有问题。
C c[10]
不是多态类型。您可能能够获得指向数组中第一项的指针,但那仍然只是一个 C
。
如果您尝试将其转换为 B
,您将得到切片。
C* c = new C();
可以是 dynamic_cast
到 B
.
我认为这是一个 gcc 错误。代码在 clang 上编译。
首先,两位候选人都是可行的。来自 [转化]:
A standard conversion sequence is a sequence of standard conversions in the following order:
— Zero or one conversion from the following set: lvalue-to-rvalue conversion, array-to-pointer conversion, and function-to-pointer conversion.
— Zero or one conversion from the following set: integral promotions, floating point promotion, integral conversions, floating point conversions, floating-integral conversions, pointer conversions, pointer to member conversions, and boolean conversions.
对 foo
的两次调用都涉及数组到指针的转换(从 C[10]
到 C*
),然后是指针转换(从 C*
到A*
或 B*
)。这是允许的标准转换。
现在,我们如何对这些转化进行排名?有趣的是,标准中的行 完全 我们的用例 [over.ics.rank]:
Two conversion sequences with the same rank are indistinguishable unless one of the following rules applies:
— If class B is derived directly or indirectly from class A and class C is derived directly or indirectly from B,
— conversion of C* to B* is better than conversion of C* to A*
我们有两个相同等级(Conversion)的转换序列,它们都是可行的,但一个被认为比另一个更好。代码应该明确地更喜欢 foo(B* )
而不是 foo(A* )
。 c
被声明为一个数组这一事实不应该使它变得模棱两可。