c++ - 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 类型。
解决方案
类初始化
对于具有用户定义构造函数的类Foo
,初始化之间的唯一区别是最后一个(称为复制初始化)等价于
Foo bar3 = Foo(5);
也就是说,初始化表达式被转换为类类型(通过构造函数),然后从它bar3
初始化。(在 C++17 之前,这在理论上涉及复制或移动,但编译器通常会避免这种开销。)
请注意,还有一种语法:
Foo bar4={5};
这被称为copy-list-initialization,但与没有的版本的唯一区别=
是explicit
不允许构造函数。
结构初始化
这些形式之间缺乏显着差异无法激发拥有它们,因此令人困惑。区别来自于容器,广义地解释为包括聚合(简单的类似 C 的struct
s)。那些支持{}
-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执行)。
正是这个额外对象的存在与 不同Foo
,int
而不必根据内存布局在操作上定义一个类:在 aFoo
上允许的操作通常是不同的,因为它不同于它可能包含的任何对象。
推荐阅读
- google-fabric - 不同应用上的相同OOM曲线
- python - Django添加全局变量
- python - Dataframe.str 因整列为空白而失败
- javascript - 谷歌地图 API 地理编码
- apache-kafka - Kafka - Confluent Cloud - 状态和限制是什么?
- regex - 如何使用 perl 或 sed 等命令行工具替换 LaTex $ 分隔符?
- batch-file - 用于解析 XML 文件并将文件复制到不同文件夹的批处理文件
- r - 使用solnp函数在R中优化具有两个参数和约束的函数?
- powershell - 使用 X509 客户端证书的 multipart/form-data API POST 调用
- python - 为什么 Celery 在 Flask 应用中有不同的 Python Path