数组作为指针传递的不明确重载

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_castB.

我认为这是一个 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 被声明为一个数组这一事实不应该使它变得模棱两可。