#include <iostream>
using namespace std;
class Test{
private:
Test(int a, int b=0)
{
cout << "private constructor\n";
}
public:
Test(int a)
{
cout << "public constructor\n";
}
};
int main()
{
Test t(1);
}
当我尝试编译代码gcc
时说:
test.cpp: In function ‘int main()’:
test.cpp:20:10: error: call of overloaded ‘Test(int)’ is ambiguous
Test t(1);
^
test.cpp:12:2: note: candidate: Test::Test(int)
Test(int a)
^
test.cpp:7:2: note: candidate: Test::Test(int, int)
Test(int a, int b=0)
^
test.cpp:5:7: note: candidate: Test::Test(const Test&)
class Test{
^
和clang
说:
test.cpp:20:7: error: call to constructor of 'Test' is ambiguous
Test t(1);
^ ~
test.cpp:7:2: note: candidate constructor
Test(int a, int b=0)
^
test.cpp:12:2: note: candidate constructor
Test(int a)
^
test.cpp:5:7: note: candidate is the implicit copy constructor
class Test{
^
1 error generated.
模棱两可的原因是什么?由于Test(int,int)
是私有的,因此无法在Test t(1)
中调用它。一个可能的答案是(我最初的想法),它使得两个相同的构造函数签名成为可能,即Test()
可以在私有构造函数中只调用一个int
。但是在程序代码中Test t(1)
仅对公共构造函数可行,因此它不应该提供私有构造函数作为候选者。为什么这么说?
答案 0 :(得分:5)
根据标准,显而易见的原因是模棱两可的:
应该注意的是,它可以访问成员和基类 被控制,而不是他们的可见性。成员的名字仍然是 对基类的可见和隐式转换仍然存在 当这些成员和基类无法访问时。该 建立对给定构造的解释而不考虑 访问控制。如果建立的解释利用 不可访问的成员名称或基类,构造是 不良形成。
这种可见性意味着编译器必须考虑构造的两个重载,并且它们对于你传递的参数同样有用。
由于构造函数是私有的,因此只能使用类及其成员的范围进行访问,因此只需删除默认参数值即可。您可以通过其他方式在类定义中维护此默认值。例如,通过在类实现文件中引入一个常量:
int const default_b = 0;
// ...
return Test{a, default_b};