C++ 原始类型初始化 v.s。对象初始化

C++ Primitive Type Initialization v.s. Object Initialization

我很好奇 C++ 基元内置类型(例如 int)与 class 的对象相比如何初始化。

经过研究,我了解到 C++ 是一种静态类型语言,这意味着类型检查是在编译时而不是 运行 时完成的。这意味着,原始类型 不是 对象 class 并且类型不能更改。

以下对象初始化有何不同:

class Foo
{
public:
    int num;
    Foo(int n) : num(n) {}
};

Foo bar(5);
Foo bar2{ 5 };
Foo bar3 = 5;

原始初始化:

int num(5);
int num2{ 5 };
int num3 = 5;

我知道 Foo 的实例调用构造函数进行初始化,但如果它不是对象,原始调用或做什么来初始化?

此外,还有什么从根本上区分了 Foo 和 int 类型,除了 Foo 是 "a user defined blue print to create instances" 和 int 是 "a non object built in type"。

Class初始化

对于具有像 Foo 这样的用户定义构造函数的 class,初始化之间的唯一区别是最后一个(称为 复制初始化 )相当于

Foo bar3 = Foo(5);

即初始化表达式被转换为class类型(通过一个构造函数)然后bar3从[=59=初始化]那个。 (在 C++17 之前,这在概念上涉及复制或移动,但编译器通常会避免这种开销。)

注意还有一种语法:

Foo bar4={5};

这称为 copy-list-initialization,但与没有 = 的版本的唯一区别是不允许使用 explicit 构造函数。

结构初始化

这些形式之间缺乏显着差异,无法激发使用它们的动机,因此令人困惑。 containers 有区别,广义上解释为包括 aggregates(简单的 C-like structs)。那些支持{}-具有不同含义的初始化,即构造一个对象包含一些数据,而不是从中计算。所以

std::vector<double> a(10,1),b{10,1};

定义 a 有 10 个值(每个为 1),b 定义有两个值 10 和 1。

有人建议,使用花括号进行初始化应该限制在这个意思上,以避免混淆。

原始初始化

最后,我们有您的 int 个例子。现在应该清楚所有的初始化都是可以互换的(除了 list-initialization 禁止缩小转换),因为计算原始值和填充它之间没有区别。也不可能观察到原始类型变量的初始化(或赋值):它只是将值提供为抽象机器的原子操作。 (编译器知道这一点并尽可能多地省略此类变量以提高效率。)

对象

即使 int 也是一个对象(在 C++ 中这个词的含义,而不是 Java 或 Python 的含义),并且当您有一个 Foo你有两个对象: Foo 本身和它包含的 int num (与它一起创建和销毁)。因此,您对 Foo 对象的初始化也是每个初始化两次:外部 内部(始终由 num(n) 成员初始化器).

正是这个额外对象的存在将 Fooint 区分开来,而无需根据内存布局在操作上定义 class: Foo 通常是不同的,因为它与它可能包含的任何对象 不同