为啥类的常量数据成员需要在构造函数中初始化?

Posted

技术标签:

【中文标题】为啥类的常量数据成员需要在构造函数中初始化?【英文标题】:Why constant data member of a class need to be initialized at the constructor?为什么类的常量数据成员需要在构造函数中初始化? 【发布时间】:2012-05-25 17:19:53 【问题描述】:

我想知道为什么类的常量数据成员需要在构造函数中初始化,为什么不在其他地方初始化?这样做和不这样做有什么影响?

我还看到只有静态常量整数数据可以在类内初始化,而不是在类内初始化非数据成员。

例如:- 假设下面是我的类声明

class A
     int a; // This we can initialize at the constructor or we can set this member by calling "vSet" member function
     const int b;
     static const int c = 10; //This works fine
public:
     A();
     ~A();
     void vSet(int a);
     int iAdd();
     void vDisplay();    
;

而构造函数定义如下:-

已编辑部分:由于之前的构造函数定义示例错误

 A::A():a(1),b(9)

如果我错了,请纠正我。 提前致谢。

【问题讨论】:

非常感谢大家的宝贵意见。 【参考方案1】:
A::A()
      a = 1;
      b = 9; // Why we need to initialize this only at the constructor. 
   

不是初始化,而是赋值ab 是已经构建并且在这种情况下您为它们分配值。 const 限定符要求变量在初始化后不要更改,允许此分配将破坏该约定。

这是使用成员初始化列表进行的初始化。

A::A():a(1),b(9)

您可能想看看我的这个答案以了解区别:

What is the difference between Initializing and Assignment inside constructor?


关于另一个问题,关于类中只能初始化静态常量整数数据,请阅读我的这个答案,其中有更详细的解释:

Why I can't initialize non-const static member or static array in class?

【讨论】:

除上述区域外,无论您提到什么。我们可以在类中的其他位置进行初始化吗?提前致谢 @Abhineet:是的,您可以在 C++11 中使用就地初始化。看我的回答。 @Abhineet:查看我之前在第二个链接中的回答,它详细解释了 C++11 中放宽了类内初始化规范的基本原理和事实。 非常感谢您的宝贵意见。【参考方案2】:

您所做的不是初始化。它是赋值,所以b=9 甚至不会编译,因为bconst,所以不能分配任何值给它。它应该被初始化,为此,使用成员初始化列表:

A::A() : a(1), b(9) 
   // ^^^^^^^^^^^^ this is called member-initialization list


在 C++11 中,您可以使用就地初始化:

class A

     int a = 1;       //C++11 only
     const int b = 9; //C++11 only

     static const int c = 10; //This works fine (both in C++03 and C++11)
     //...
;

【讨论】:

【参考方案3】:

因为它是常数,所以它的值不能改变。在构造函数之外的任何地方进行初始化将意味着默认初始化,然后是 assignment,这对于常量是不允许的。这相当于这样做:

const int i; // OK
i = 42; // Error!

请注意,在 C++11 中这样做是完全可以的:

struct Foo 

  const int i=42;
  const double x = 3.1416;
;

但这遵循相同的规则,即没有分配。

【讨论】:

【参考方案4】:

常量数据是永远无法更改的数据。它被初始化一次,然后永远保持相同的值。

因此,您不能在任何地方为其赋值。

然而,构造函数是初始化的地方。所以这里有一个例外,您可以为您的 const 数据分配一个值。您可以按照经典方式执行此操作,或者说像初始化列表一样。

现在,当变量不是静态变量时,为什么不能在类定义中执行此操作(与 Java 不同)是另一个问题,我不知道答案。

【讨论】:

【参考方案5】:

当你的构造函数的body被输入时,所有的成员和子对象都已经被初始化了。构造函数body唯一能做的就是改变它们——显然,const成员是不允许的。

但是,您可以使用初始化列表。

【讨论】:

【参考方案6】:

您不能在构造函数之外初始化const 成员,因为它们是const。根据定义,在它们被初始化之后就不能修改它们,并且在对象被构造之后,任何试图设置值的东西都是一种修改。

【讨论】:

【参考方案7】:

const 值是右值,因此它们不能出现在表达式的右侧,因为它具有 const 性。

所以,当你在构造函数的主体上使用这个表达式时

A::A()

    a = 1;
    b = 9; // Why we need to initialize this only at the constructor. 

正如 Als 之前提到的,您将 const 值用作左值。事实是,您正试图将一个新值赋给一个不允许在其生命周期开始后更改其值的变量。

将值分配给常量数据成员的正确方法是在 ctor 初始化器列表中,即在成员值的生命周期开始之前(如 Nawaz 所述):

A::A() :
    a(1),
    b(9)


最后,在 C++11 标准 you're allowed to initialize all data members where it was declared 上,就像静态 const 一样。

【讨论】:

以上是关于为啥类的常量数据成员需要在构造函数中初始化?的主要内容,如果未能解决你的问题,请参考以下文章

为啥不能在派生类的构造函数初始化列表中初始化基类的数据成员?

成员对象和封闭类

具有引用数据成员的类的默认构造函数?

C++:Special Member Functions

结构体的初始化(构造函数)

C++调用父类的构造函数规则