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 struct
s)。那些支持{}
-具有不同含义的初始化,即构造一个对象包含一些数据,而不是从中计算。所以
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)
成员初始化器).
正是这个额外对象的存在将 Foo
与 int
区分开来,而无需根据内存布局在操作上定义 class: Foo
通常是不同的,因为它与它可能包含的任何对象 不同 。
我很好奇 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 struct
s)。那些支持{}
-具有不同含义的初始化,即构造一个对象包含一些数据,而不是从中计算。所以
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)
成员初始化器).
正是这个额外对象的存在将 Foo
与 int
区分开来,而无需根据内存布局在操作上定义 class: Foo
通常是不同的,因为它与它可能包含的任何对象 不同 。