在常量成员

时间:2016-08-24 13:08:39

标签: c++ constructor initialization const

为什么编译器(clang)抱怨mymy未初始化,当我特意告诉它是一个常量值时,持有50.为什么它允许我将它改为23 ..当我还告诉他不变的时候?

#include <iostream>

class Base
{
public:

    Base(int y) : my(y) {std::cout << "Base:" << my << std::endl;}
private:
    int my;
};

class Derived : public Base
{
public:
    Derived() : Base(mymy), mymy(23) {std::cout << "Derived:" << mymy << std::endl;}


private:

    const int mymy = 50;
};

int main()
{
    Derived a;
}
奇怪的是,coliru没有点击就编译了。 http://coliru.stacked-crooked.com/a/63629c2d99bf6f43(是的,我知道将其更改为static将解决此问题)

2 个答案:

答案 0 :(得分:4)

标准说(§12.6.2/ 10 1 ,重点是我的):

  

如果给定的非静态数据成员同时具有默认成员初始值设定项和 mem-initializer ,则初始化   执行 mem-initializer 指定,忽略非静态数据成员的默认成员初始值设定项。 [示例:给定

struct A {
      int i = /* some integer expression with side effects */ ;
      A(int arg) : i(arg) { }
      // ...
};
     

A(int)构造函数只会将i初始化为arg的值,并且i的默认成员初始化程序中的副作用将不会发生。 -end example ]

http://coliru.stacked-crooked.com/使用g ++但不会产生警告,但结果是相同的:Base未使用5023进行初始化,但使用0进行初始化。您可以通过在mymy之前添加其他属性来获取更奇怪的行为:

class Derived: public Base {
  public:
  Derived() : Base(mymy), mymymy(mymy), mymy(23) {
      std::cout << "Derived:" << mymy << std::endl;
      std::cout << "Derived:" << mymymy << std::endl;

  }
  int mymymy;
  const int mymy = 50;
};

coliru的输出:

Base:4197208
Derived:23
Derived:4197208
Main:23

但是如果你在mymy之后添加一个属性:

class Derived : public Base {
  public:
  Derived() : Base(mymy), mymy(23) {
      std::cout << "Derived:" << mymy << std::endl;
      std::cout << "Derived:" << mymymy << std::endl;

  }
  const int mymy = 50;
  int mymymy= mymy;

};

将使用您在构造函数的member-initializer-list中提供的值:

Base:0
Derived:23
Derived:23
Main:23

关于const限定:您始终可以在构造函数的member-list-initializer中初始化const成员(这是您可以将它们与默认成员初始化程序一起初始化的唯一位置)。

我不知道该标准是否有更明确的引用,但§12.6.2/ 7 1 (虽然这个例子非常明确):

  

mem-initializer 中的表达式列表 braced-init-list 用于初始化指定的子对象(或者,委托构造函数的情况,完整的类对象)根据8.5的初始化规则进行直接初始化。   [示例:

struct B1 { B1(int); /* ... */ };
struct B2 { B2(int); /* ... */ };
struct D : B1, B2 {
    D(int);
    B1 b;
    const int c;
};
D::D(int a) : B2(a+1), B1(a+2), c(a+3), b(a+4)
    { /* ... */ }
D d(10);
     

- 示例]

1 最新的C ++ 17标准草案(N4594)。

答案 1 :(得分:3)

如果使用ctor初始化程序,则忽略类初始化。

考虑使用参数mymy

调用基础构造函数
Derived() : Base(mymy), mymy(23) {std::cout << "Derived:" << mymy << std::endl;}

不正确,因为派生类的数据成员尚未初始化。