C ++ 11允许非静态和非const成员的类内初始化。有什么改变? [英] C++11 allows in-class initialization of non-static and non-const members. What changed?

查看:213
本文介绍了C ++ 11允许非静态和非const成员的类内初始化。有什么改变?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在C ++ 11之前,我们只能对积分或枚举类型的静态const成员执行类的初始化。 Stroustrup在其C ++常见问题中进行了讨论,提供了以下示例:

Before C++11, we could only perform in-class initialization on static const members of integral or enumeration type. Stroustrup discusses this in his C++ FAQ, giving the following example:

class Y {
  const int c3 = 7;           // error: not static
  static int c4 = 7;          // error: not const
  static const float c5 = 7;  // error: not integral
};

以下推理:


那么为什么会出现这些不方便的限制呢?类通常在头文件中声明,并且头文件通常包括在许多翻译单元中。但是,为了避免复杂的链接器规则,C ++要求每个对象都有唯一的定义。如果C ++允许需要在内存中作为对象存储的实体的类定义,那么该规则将被破坏。

So why do these inconvenient restrictions exist? A class is typically declared in a header file and a header file is typically included into many translation units. However, to avoid complicated linker rules, C++ requires that every object has a unique definition. That rule would be broken if C++ allowed in-class definition of entities that needed to be stored in memory as objects.

++ 11放宽了这些限制,允许非静态成员的类初始化(§12.6.2/ 8):

However, C++11 relaxes these restrictions, allowing in-class initialization of non-static members (§12.6.2/8):


非委托构造函数,如果给定的非静态数据成员或基类不是由mem-initializer-id 指定的(包括没有 mem-initializer- / em>,因为构造函数没有 ctor-initializer ),而实体不是抽象类(10.4)的虚拟基类,则

In a non-delegating constructor, if a given non-static data member or base class is not designated by a mem-initializer-id (including the case where there is no mem-initializer-list because the constructor has no ctor-initializer) and the entity is not a virtual base class of an abstract class (10.4), then


  • 如果实体是具有 brace-or-equal-initializer 的非静态数据成员,则实体按8.5中的规定初始化;

  • 否则,如果实体是变量成员(9.5),则不执行初始化;

  • if the entity is a non-static data member that has a brace-or-equal-initializer, the entity is initialized as specified in 8.5;
  • otherwise, if the entity is a variant member (9.5), no initialization is performed;
  • otherwise, the entity is default-initialized (8.5).

如果使用 constexpr 说明符标记非静态成员,9.4.2节也允许类的初始化。

Section 9.4.2 also allows in-class initialization of non-const static members if they are marked with the constexpr specifier.

那么对C ++ 03中的限制的原因发生了什么?

So what happened to the reasons for the restrictions we had in C++03? Do we just simply accept the "complicated linker rules" or has something else changed that makes this easier to implement?

推荐答案

我们只是简单地接受复杂的链接器规则答案是他们保持链接器大致相同,代价是使编译器比以前更复杂。

The short answer is that they kept the linker about the same, at the expense of making the compiler still more complicated than previously.

Ie,而不是导致多个定义链接器来整理,它仍然只导致一个定义,编译器必须排序。

I.e., instead of this resulting in multiple definitions for the linker to sort out, it still only results in one definition, and the compiler has to sort it out.

它还导致一些更复杂的规则为程序员,以保持整理,但它是最简单的,这不是一个大交易。当为单个成员指定两个不同的初始值设置时,额外的规则就会出现:

It also leads to somewhat more complex rules for the programmer to keep sorted out as well, but it's mostly simple enough that it's not a big deal. The extra rules come in when you have two different initializers specified for a single member:

class X { 
    int a = 1234;
public:
    X() = default;
    X(int z) : a(z) {}
};

现在,额外的规则在这一点处理什么值用于初始化 a 时使用非默认构造函数。答案是相当简单的:如果你使用没有指定任何其他值的构造函数,那么 1234 将用于初始化 a - 但如果您使用指定其他值的构造函数,则 1234 基本上被忽略。

Now, the extra rules at this point deal with what value is used to initialize a when you use the non-default constructor. The answer to that is fairly simple: if you use a constructor that doesn't specify any other value, then the 1234 would be used to initialize a -- but if you use a constructor that specifies some other value, then the 1234 is basically ignored.

例如:

#include <iostream>

class X { 
    int a = 1234;
public:
    X() = default;
    X(int z) : a(z) {}

    friend std::ostream &operator<<(std::ostream &os, X const &x) { 
        return os << x.a;
    }
};

int main() { 
    X x;
    X y{5678};

    std::cout << x << "\n" << y;
    return 0;
}

结果:

1234
5678

这篇关于C ++ 11允许非静态和非const成员的类内初始化。有什么改变?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆