首页 > 解决方案 > C++ 原始类型初始化与对象初始化

问题描述

我很好奇内置类型的 C++ 原语,例如 int,与类的对象相比是如何初始化的。

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

那么以下对象初始化有什么不同:

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 和 int 类型。

标签: c++oopobjectinitializationprimitive-types

解决方案


类初始化

对于具有用户定义构造函数的类Foo,初始化之间的唯一区别是最后一个(称为复制初始化)等价于

Foo bar3 = Foo(5);

也就是说,初始化表达式被转换为类类型(通过构造函数),然后从bar3初始化。(在 C++17 之前,这在理论上涉及复制或移动,但编译器通常会避免这种开销。)

请注意,还有一种语法:

Foo bar4={5};

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

结构初始化

这些形式之间缺乏显着差异无法激发拥有它们,因此令人困惑。区别来自于容器,广义地解释为包括聚合(简单的类似 C 的structs)。那些支持{}-initialization 具有不同的含义,即构造一个包含一些数据的对象,而不是从中计算出来的。所以

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

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

有人建议使用大括号进行初始化应限于此含义以避免混淆。

原语初始化

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

对象

甚至 anint也是一个对象(在这个词的 C++ 意义上,而不是 Java 或 Python 意义上),当你有 a 时,Foo你有两个对象:它Foo本身和int num它包含的(它与它一起被创建和销毁)。因此,您对Foo对象的初始化也是两个初始化:外部初始化内部初始化组成(始终由num(n) member-initializer执行)。

正是这个额外对象的存在与 不同Fooint而不必根据内存布局在操作上定义一个类:在 aFoo上允许的操作通常是不同的,因为它不同于它可能包含的任何对象。


推荐阅读