#include<iostream>
using namespace std;
class A {
public:
int i;
};
int main() {
const A aa; //This is wrong, I can't compile it! The implicitly-defined constructor does not initialize ‘int A::i’
}
当我使用
时class A {
public:
A() {}
int i;
};
这没关系!我可以编译它!为什么我在使用隐式定义的构造函数时无法编译它?
答案 0 :(得分:10)
为什么隐式定义的构造函数不起作用?
它确实有效,但其中一条语言规则是它不能用于初始化const
对象,除非它初始化所有成员;并且它不会像int
这样的普通类型初始化成员。这通常是有道理的,因为const
以后没有办法给他们一个值。
(这是一个轻微的简化;请参阅语言标准的章节和经文的评论。)
如果你定义了自己的构造函数,那么你就说你知道自己在做什么,并且不希望该成员初始化。即使对于const
对象,编译器也允许您使用它。
如果要将其设置为零,则可以初始化对象:
const A aa {}; // C++11 or later
const A aa = A(); // historic C++
如果要将其设置为其他值,或者将其设置为零而用户不必指定值初始化,那么您需要一个初始化成员的构造函数:
A() : i(whatever) {}
答案 1 :(得分:9)
为什么隐式定义的构造函数不起作用?
因为C ++标准是这样说的:
[dcl.init] 第7段:
如果程序要求对const限定类型T
的对象进行默认初始化,则T
应为具有用户提供的默认构造函数的类类型。
这可确保您不会创建包含以后无法初始化的未初始化数据的const
对象。
要初始化const限定对象,您需要拥有用户提供的默认构造函数或使用初始化器:
const A aa = A();
此处使用表达式aa
初始化对象A()
,该表达式是值初始化对象。您可以在没有默认构造函数的情况下对类类型进行值初始化,因为如果类型没有默认构造函数,则值初始化将值设置为零。
但是,标准中的规则过于严格,因为它禁止使用隐式定义的构造函数,即使没有数据成员或所有数据成员都有合理的默认构造函数,因此存在针对提议更改的标准的缺陷报告它,请参阅issue 253。
答案 2 :(得分:2)
您没有说明您正在使用的编译器。我已经尝试过使用VS2012并收到警告C4269。
这是一个问题的原因是因为aa
是const
。因为您尚未定义构造函数,所以使用了默认构造函数,因此i
可以是任何东西。它也无法更改(因为aa
是const)。
如果您定义构造函数,则假定您对i
的初始化感到满意。虽然,在这种情况下,您实际上并没有改变行为。
由于该类的实例是在堆栈上生成的,因此m_data的初始值可以是任何值。此外,由于它是一个const实例,因此永远不能更改m_data的值。
答案 3 :(得分:0)
因为i
未初始化。
class A
{
public:
A()
{
i =0;
}
int i;
};
“隐式构造函数”表示自动为您生成的构造函数并生成错误,因为它意识到它无法初始化i
的值。这可以是无参数构造函数,复制构造函数或(从C ++ 11开始)移动构造函数。
答案 4 :(得分:0)
为什么隐式定义的构造函数不起作用?
它工作得很好,但它没有隐式决定你的默认值(因此,它只为它的成员调用默认构造函数,但不为POD类型调用)。
如果您希望构造函数使用某些值初始化您的成员,则必须显式写入(即显式添加默认构造函数)。
使用默认(隐式)构造函数初始化具有所选值的POD成员(例如,如零)将在您不需要时添加额外的计算周期(并减慢程序速度)。 C ++的行为就好像你(程序员)知道你在做什么(即如果你没有明确地初始化你的成员,编译器假设你不关心你得到什么默认值。)