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

C++ 数组作为指针传递的不明确重载,c++,arrays,pointers,overloading,C++,Arrays,Pointers,Overloading,下面的代码 #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 *

下面的代码

#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);
}
我得到一个编译器错误,说

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
函数中访问它们,您就会遇到问题,正如所解释的,因为
foo(B*)
函数无法知道它实际上在处理可能占用更多内存空间的
C
对象。所以不要这样做


尽管如此,我仍然有兴趣理解为什么编译器在这里抱怨歧义,因为我真的不认为这有什么问题。

C[10]
不是多态类型。您可能能够获得指向数组中第一项的指针,但这仍然只是一个
C

如果您尝试将其强制转换为
B
,则会得到切片


C*C=newc()可以是动态的
B
C[10]
不是多态类型。您可能能够获得指向数组中第一项的指针,但这仍然只是一个
C

如果您尝试将其强制转换为
B
,则会得到切片


C*C=newc()可以是
动态的
B

我相信这是一个gcc错误。代码在叮当声中编译

首先,两位候选人都是可行的。从[conv]:

标准转换序列是按以下顺序进行的标准转换序列:
-以下集合的零或一个转换:左值到右值转换,数组到指针转换, 和函数到指针的转换。
-以下集合的零或一次转换:整数提升、浮点提升、整数 转换,浮点转换,浮点积分转换,指针转换,指针到 成员转换和布尔转换

foo
的两个调用都涉及数组到指针的转换(从
C[10]
C*
),然后是指针转换(从
C*
a*
B*
)。这是允许的标准转换

现在,我们如何对这些转换进行排序?有趣的是,标准中的行与我们的用例完全匹配,在[over.ics.rank]中:

具有相同秩的两个转换序列 除非下列规则之一适用,否则无法区分:
-如果B类直接或间接源自A类,C类直接或间接源自 B、
-将C*转换为B*比将C*转换为A*更好。


我们有两个相同等级(转换)的转换序列,它们都是可行的,但一个被认为比另一个更好。代码应该明确地选择
foo(B*)
而不是
foo(A*)
c
被声明为数组这一事实不应使其模棱两可

我认为这是一个gcc错误。代码在叮当声中编译

首先,两位候选人都是可行的。从[conv]:

标准转换序列是按以下顺序进行的标准转换序列:
-以下集合的零或一个转换:左值到右值转换,数组到指针转换, 和函数到指针的转换。
-以下集合的零或一次转换:整数提升、浮点提升、整数 转换,浮点转换,浮点积分转换,指针转换,指针到 成员转换和布尔转换

foo
的两个调用都涉及数组到指针的转换(从
C[10]
C*
),然后是指针转换(从
C*
a*
B*
)。这是允许的标准转换

现在,我们如何对这些转换进行排序?有趣的是,标准中的行与我们的用例完全匹配,在[over.ics.rank]中:

具有相同秩的两个转换序列 除非下列规则之一适用,否则无法区分:
-如果B类直接或间接源自A类,C类直接或间接源自 B、
-将C*转换为B*比将C*转换为A*更好。


我们有两个相同等级(转换)的转换序列,它们都是可行的,但一个被认为比另一个更好。代码应该明确地选择
foo(B*)
而不是
foo(A*)
c
被声明为数组这一事实不应使其模棱两可

在vs2008上,我无法重现错误-后一个测试用例打印“B”。foo(&c[0])是否有效?。不管怎么说,这个想法是从哪里来的?此外,当您将
C
数组转换为指向
B
(或
A
)的指针时,数组访问所需的指针算法将无法实现;一旦
C
包含一些数据成员,
b[1]
将不会为您提供有效的对象,因为
sizeof(b)!=sizeof(C)
(在此之前也是未定义的行为)。在foo(B*)中,您可以通过使用dynamic_cast知道它是否是C。C*C=foo(b*b)中的动态_cast(b),并检查C是否为NULL ptr(或NULL für C++0x)。如果不是nullptr,则为C。@Gombat这些类不是多态的,您不能使用
dynamic\u cast
。在vs2008上,我无法重现错误-后一个测试用例打印“B”。foo(&C[0])有效吗?。不管怎么说,这个想法是从哪里来的?此外,当您将
C
数组转换为指向
Btest_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*)