在类初始化常量成员时

In class initialization of constant member

本文关键字:成员 常量 初始化      更新时间:2023-10-16

为什么编译器(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将解决此问题)

标准规定(§12.6.2/101,重点是我的):

如果给定的非静态数据成员既具有默认成员初始化式又具有mem初始化式,则执行由mem初始化式指定的,忽略非静态数据成员的默认成员初始化式。[示例:给定

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

A(int)构造函数将简单地将i初始化为arg的值,并且i的默认成员初始化器中的副作用不会发生。端例子)

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

在构造函数的成员初始化列表中提供的值将被使用:

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

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

我不知道标准中是否有更明确的引用,但是§12.6.2/71(这个例子很明确):

mem-initializer中的expression-list带括号的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);

-end example]


1

<子><一口>最新c++ 17标准草案(N4594)。

如果你使用了tor初始化器,那么在类初始化中会被忽略。

考虑调用实参为mymy的基类构造函数

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

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