10
#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;
};

还行吧!我可以编译它!为什么我使用隐式定义的构造函数时无法编译它?

4

5 回答 5

10

为什么隐式定义的构造函数不起作用?

它确实有效,但语言规则之一是它不能用于初始化const对象,除非它初始化所有成员;并且它不会初始化具有诸如int. 这通常是有道理const的,因为以后没有办法给他们一个价值。

(这是一个轻微的简化;请参阅语言标准中章节和经文的注释。)

如果您定义自己的构造函数,那么您就是在说您知道自己在做什么并且不希望该成员被初始化。编译器甚至可以让您将其用于const对象。

如果要将其设置为零,则可以对对象进行值初始化:

const A aa {};    // C++11 or later
const A aa = A(); // historic C++

如果您想将其设置为另一个值,或者将其设置为零而无需用户指定值初始化,那么您将需要一个初始化该成员的构造函数:

A() : i(whatever) {}
于 2013-10-01T08:48:37.083 回答
9

为什么隐式定义的构造函数不起作用?

因为 C++ 标准是这样说的:

[dcl.init]第 7 段: 如果程序要求对 const 限定类型的对象进行默认初始化TT则应是具有用户提供的默认构造函数的类类型。

这可确保您不会创建const包含以后无法初始化的未初始化数据的对象。

要初始化一个 const 限定的对象,您需要有一个用户提供的默认构造函数或使用初始化器:

const A aa = A();

这里的对象是用一个值初始化对象aa的表达式来初始化的。A()您可以在没有默认构造函数的情况下对类类型进行值初始化,因为如果该类型没有默认构造函数,值初始化会将值设置为零。

但是,标准中的规则过于严格,因为即使没有数据成员或所有数据成员都有合理的默认构造函数,它也禁止使用隐式定义的构造函数,因此有一份针对标准的缺陷报告建议对其进行更改,请参阅第 253 期

于 2013-10-01T09:06:41.093 回答
2

你没有说明你正在使用什么编译器。我已经用 VS2012 尝试过这个并收到警告C4269

这是一个问题的原因是aa因为const. 因为您还没有定义构造函数,所以使用了默认构造函数,因此i可以是任何构造函数。它也无法更改(因为aa是 const)。

如果您定义了一个构造函数,则假定您对i. 虽然,在这种情况下,您实际上并没有改变行为。

从这个MSDN 页面

由于该类的实例是在堆栈上生成的,因此 m_data 的初始值可以是任何值。此外,由于它是一个 const 实例,因此 m_data 的值永远不能更改。

于 2013-10-01T08:54:55.030 回答
0

因为i没有初始化。

class A 
{ 
    public:
    A()
    {
        i =0;
    }
    int i;
};

“隐式构造函数”是指自动为您生成的构造函数,并生成错误,因为它意识到它无法初始化i. 这可以是无参数构造函数、复制构造函数或(从 C++11 开始)移动构造函数。

于 2013-10-01T08:41:43.400 回答
0

为什么隐式定义的构造函数不起作用?

它工作得很好,但它不能隐式决定你的默认值是什么(因此,它只为它的成员调用默认构造函数,而不是为 POD 类型调用)。

如果您希望构造函数使用某些值初始化您的成员,则必须显式编写(即显式添加默认构造函数)。

当您不需要时,使默认(隐式)构造函数使用所选值(例如零)初始化 POD 成员会增加额外的计算周期(并减慢程序速度)。C++ 旨在表现得好像您(程序员)知道自己在做什么(即,如果您没有显式地初始化您的成员,编译器会假定您不关心您获得的默认值)。

于 2013-10-01T08:47:58.130 回答