- 令我惊讶的是,我发现 c++ 对象的名称可以与类名相同。有人可以向我解释原因吗?
- 当我将类的对象声明
a
为a a1()
时,它不会引发错误,但不会调用构造函数。为什么会这样?
我的代码:
#include<iostream>
using namespace std;
class a
{
public:
a()
{
cout << "in a\n";
}
};
int main()
{
a a1();
a a;
}
a
为a a1()
时,它不会引发错误,但不会调用构造函数。为什么会这样?我的代码:
#include<iostream>
using namespace std;
class a
{
public:
a()
{
cout << "in a\n";
}
};
int main()
{
a a1();
a a;
}
当您编写a a1();
它时,它实际上被解析为函数声明,而不是对默认构造函数的调用。
a a1;
将正确调用默认构造函数
当您编写a a;
它时,它可以工作,因为在所谓的名称隐藏中变量名优先于类名,但即使它有效,它只会导致混乱,我会避免这样做。
对于所有喜欢标准报价的人来说,你去吧
类名 (9.1) 或枚举名 (7.2) 可以被同一范围内声明的变量、数据成员、函数或枚举数的名称隐藏。如果一个类或枚举名称和一个变量、数据成员、函数或枚举器以相同的名称在同一范围内(以任何顺序)声明,则无论变量、数据成员、函数或枚举器名称可见。
a a1();
是一个函数声明。
这是在 C++11 中创建统一初始化的一个重要原因。要使用 C++11 中的构造函数初始化对象,请使用a a1{};
实际上,如果您查看C++ 草案标准部分 3.3.10
名称隐藏第2段说(强调我的) ,使用变量隐藏类的名称是有效的:
类名 (9.1) 或枚举名 (7.2) 可以被同一范围内声明的变量、数据成员、函数或枚举器的名称隐藏。如果一个类或枚举名称和一个变量、数据成员、函数或枚举器以相同的名称在同一范围内(以任何顺序)声明,则无论变量、数据成员、函数或枚举器名称可见。
我认为这不是一个好的做法,它会导致难以维护代码。这行代码实际上是在声明一个函数:
a a1();
您也可以使用这个 pre -C++11:
a a1 ;
或C++11中引入的统一初始化:
a a1{} ;
回到name hide,我惊喜地发现clang
无论设置的警告级别如何,都会使用此代码警告您:
int main()
{
a a;
a a2 ;
}
我收到这条消息:
main.cpp:12:10: note: class 'a' is hidden by a non-type declaration of 'a' here
a a;
^
虽然我看不到从gcc
.
更新
考虑到我之前在统一初始化的问题上发表的评论,我意识到如果您怀疑这a1
不是正确的类型,您可以使用typeid来调试正在发生的事情。例如这段代码:
std::cout << typeid(a).name() << std::endl ;
std::cout << typeid(a1).name() << std::endl ;
在Coliru live example上产生此输出:
1a
F1avE
并通过c++filt传递它,您会收到以下输出:
a () // A function that returns type a
a // type a
a a1();
是一个函数声明返回类型,a
它与调用构造函数无关
a a ;
很简单的语句工作正常会调用构造函数
这是我尝试用 编译它时从你的代码中得到的clang
,我认为它说明了一切。
test.cpp:15:9: warning: empty parentheses interpreted as a function declaration
[-Wvexing-parse]
a a1();
^~
test.cpp:15:9: note: remove parentheses to declare a variable
a a1();
^~
1 warning generated.