我很好奇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是"一个非对象内置类型"。
答案 0 :(得分:0)
对于具有用户定义的构造函数(例如Foo
)的类,初始化之间的唯一区别是最后一个(称为 copy-initialization )等效于
Foo bar3 = Foo(5);
也就是说,初始化器表达式被转换为类类型(通过构造器通过),然后从{em> that 初始化bar3
。 (直到C ++ 17,这在概念上涉及复制或移动,但是编译器通常会避免这种开销。)
请注意,还有一种语法:
Foo bar4={5};
这称为 copy-list-initialization ,但与没有=
的版本唯一的区别是不允许使用explicit
构造函数。
这些形式之间没有明显的差异,不足以促使人们拥有它们,因此令人困惑。区别在于容器,广义地解释为包括聚合(简单的类似于C的struct
s)。那些支持具有不同含义的{}
初始化,这就是构造一个包含 数据的对象,而不是根据其中的 computing 。所以
std::vector<double> a(10,1),b{10,1};
将a
定义为10个值(分别为1),将b
定义为两个值10和1。
已建议使用花括号进行初始化应仅限于此含义,以免造成混淆。
最后,我们有您的int
示例。现在应该清楚所有初始化都是可以互换的(除了 list-initialization 禁止缩小转换范围),因为在计算原始值和填充原始值之间没有区别。观察原始类型变量的初始化(或赋值)也没有任何可能:它只是将值提供为抽象机的原子动作。 (编译器知道这一点,并为了提高效率而尽可能多地忽略了这些变量。)
即使一个int
是一个对象(从C ++的意义上讲,也不是Java或Python的意义),并且当您拥有一个Foo
时,您有两个对象:{{1} }本身及其包含的Foo
(与之一起创建和销毁)。因此,您对int num
对象的初始化也是两个初始化:外部的由组成,内部的(由Foo
member-initializer < / em>)。
正是这个额外对象的存在将num(n)
与Foo
区别开来,而不必根据内存布局在操作上定义类:int
上允许的操作是总的来说有所不同,因为它与可能包含的任何对象不同。