C++对象实例化:带空括号的声明调用哪个构造函数?
解析C++中那些“没调用构造函数”的对象初始化语句
你遇到的是C++里臭名昭著的最令人头疼的解析(Most Vexing Parse)问题——这些标注???的语句根本不是在创建对象,而是被编译器解析成了函数声明,自然不会调用任何构造函数!
我们逐个拆解这些“迷惑”语句:
1. Object b();
这行代码看起来像是要默认构造一个Object对象b,但实际上编译器会把它解析成:
声明一个名为
b的函数,该函数无参数,返回值为Object类型。
完全和对象初始化无关,所以默认构造函数不会被调用。
2. Object f ( Object() ); 和 Object h ( Object() );
这两行是最典型的“最令人头疼的解析”场景。这里的Object()会被编译器解析成:
声明一个无参数、返回
Object类型的函数(而不是创建临时对象)
所以整个语句的实际含义是:
声明一个名为
f(或h)的函数,它接受一个“无参数、返回Object的函数”作为参数,返回值为Object类型。
同样,这也不是对象初始化操作,因此不会触发任何构造函数调用。
为什么会出现这种情况?
C++的语法规则有一个优先级:当一条语句既可以被解析成函数声明,又可以被解析成对象初始化时,编译器会优先选择函数声明。这就是这个“坑”的根源。
如何避免这个问题?
有几种可靠的方式绕过这个解析陷阱:
- 使用大括号初始化(列表初始化):比如把
Object b();改成Object b{};,把Object f(Object());改成Object f{Object()};(就像你代码里的c、g、i那样),大括号语法不会触发函数声明解析。 - 使用
auto推导变量类型:比如auto b = Object();(你代码里的o、p就是正确示例),这种写法明确是创建临时对象并拷贝给变量,编译器不会误解。 - 给临时对象表达式加额外括号:比如
Object f( (Object()) );,内层的括号会强制编译器把(Object())解析成临时对象,而不是函数声明,这样就会正常调用默认构造函数创建临时对象,再调用拷贝构造(不过编译器通常会优化掉拷贝,直接默认构造f)。
再确认下你代码里的正确写法
你标注为default和copy的语句都是正确的:
- 大括号初始化、
auto推导、直接赋值/拷贝初始化的写法,都能被编译器正确识别为对象创建操作,触发对应的构造函数。
内容的提问来源于stack exchange,提问作者Mansoor Ahmed Memon
相关产品推荐
相关产品推荐

