【问题标题】:In class initialization of constant member在常量成员的类初始化中
【发布时间】:2016-08-24 13:08:38
【问题描述】:

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

【问题讨论】:

  • 请注意,将mymy 传递给Base 是未定义的行为,因为它未初始化。

标签: c++ constructor initialization constants


【解决方案1】:

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

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

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;

};

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

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

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

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

mem-initializer 中的 expression-listbraced-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)。

【讨论】:

    【解决方案2】:

    如果你使用 ctor 初始化器,那么在类中的初始化将被忽略。

    考虑到带有参数mymy的基本构造函数的调用

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

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

    【讨论】:

    • 你能在标准中把我链接到这个吗?
    • 但是const 呢?编译器不应该抱怨吗?
    • @fritzone 不幸的是,我现在无法访问标准。至于 const 限定符,则 ctor 还初始化常量数据成员(静态数据成员除外)。
    • @fritzone 在last draft of the C++17 standard §12.6.2/10 中:“如果给定的非静态数据成员同时具有默认成员初始化器和 mem-initializer ,则初始化由 mem-初始化器被执行,并且非静态数据成员的默认成员初始化器被忽略。"
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-19
    • 1970-01-01
    • 2012-02-18
    相关资源
    最近更新 更多