为什么我需要一个构造函数?

时间:2013-10-01 08:40:24

标签: c++ oop constructor

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

这没关系!我可以编译它!为什么我在使用隐式定义的构造函数时无法编译它?

5 个答案:

答案 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

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

如果您定义构造函数,则假定您对i的初始化感到满意。虽然,在这种情况下,您实际上并没有改变行为。

从此MSDN page

  

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

答案 3 :(得分:0)

因为i未初始化。

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

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

答案 4 :(得分:0)

  

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

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

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

使用默认(隐式)构造函数初始化具有所选值的POD成员(例如,如零)将在您不需要时添加额外的计算周期(并减慢程序速度)。 C ++的行为就好像你(程序员)知道你在做什么(即如果你没有明确地初始化你的成员,编译器假设你不关心你得到什么默认值。)