说我有以下课程:
class A
{
public:
A() {
}
A(int a):_a(a){
}
int _a;
};
以下功能:
void someFunc (A a)
{
cout << a._a;
}
所以程序中的以下行正常工作:
someFunc (5); // Calls A(int a) Constructor.
但以下情况并非如此:
someFunc(); //Compile error
可以预期,如果它在获取整数时可以构建A, 为什么不使用默认构造函数构建一个,当没有参数调用时?
答案 0 :(得分:6)
因为someFunc()
需要一个参数而你没有提供一个没有的重载。存在从int
到A
的隐式转换,但这并不意味着您可以忽略该函数的签名并在没有参数的情况下调用它。如果您想在没有参数的情况下调用它,则会将默认值分配给a
。
void someFunc(A a = A()) {
/* stuff */
}
答案 1 :(得分:3)
因为您没有使用可转换的参数调用该函数,所以使用无参数调用该函数。这是一个不同的超载,你没有提供。
考虑以下选项:
someFunc(A())
。void someFunc (A a = A()) { ... }
。void someFunc() { someFunc(A()); }
答案 2 :(得分:1)
这是因为someFunc()
的签名与void someFunc (A a)
的签名不匹配。
根据C ++标准,第13.3.2.3节:
- 首先,要成为一个可行的函数,候选函数应该有足够的参数来与列表中的参数一致。
- 只有当(m + 1)-st参数具有默认参数时,具有m个以上参数的候选函数才可行
在这种情况下,这些都不适用,因此对于带有空参数列表的调用,void someFunc (A a)
不被视为可行。
答案 3 :(得分:0)
挑剔。从2003 C ++标准开始,
17.4.3.2.1全球名称 - ...... - 以下划线开头的每个名称都保留给实现,以用作全局名称空间中的名称
我会告诉你,使用_启动任何变量名称是不好的做法。特别是你可以将这种做法扩展到命名变量参数(int foo(int _a)),或者不考虑使用camelcase(int _MyVar)。我个人做的事情是
int a_;
你真的遇到麻烦吗?可能不是。但最好不要用下划线开始你的任何事情。从来没有名称中的任何地方有两个下划线,或者当然也是以下划线后跟大写字母开头。
答案 4 :(得分:0)
我在这里并没有真正提供答案,但它是有用的信息......有时候你真的不想允许someFunc(5)
工作,因为它可能会导致不正确的操作,或只是误导。在这种情况下,您可以将构造函数声明为explicit
:
class A
{
public:
A() {} // Are you sure you don't want to initialise _a here?
explicit A(int a) :_a(a) {}
int _a;
};
正如其他人已经说过的那样,您可以为someFunc
指定默认参数:
void someFunc( A a = A() );
现在:
someFunc(); // Calls A() by default
someFunc(5); // Not allowed because of implicit construction
someFunc(A(5)); // Caller must pass an instance of A