我想了解使用一种形式而不是另一种形式(如果有的话)的区别。
Code 1(直接在变量上初始化):
#include <iostream>
using namespace std;
class Test
{
public:
Test() {
cout<< count;
}
~Test();
private:
int count=10;
};
int main()
{
Test* test = new Test();
}
Code 2(构造函数初始化列表初始化):
#include <iostream>
using namespace std;
class Test
{
public:
Test() : count(10) {
cout<< count;
}
~Test();
private:
int count;
};
int main()
{
Test* test = new Test();
}
语义上有什么不同,或者它只是语法吗?
答案 0 :(得分:6)
在C ++核心指南中(见下面的注释1),Guideline C.48推荐了第一种方法(类内初始化器)。提供的推理是:
明确指出在所有构造函数中都应使用相同的值。避免重复。避免维护问题。它导致最短和最有效的代码。
事实上,如果你的构造函数除了初始化成员变量之外什么也没做,就像在你的问题中那样,那么Guideline C.45仍然更加坚定,并且肯定会使用类内初始化器。它解释了
使用类内成员初始值设定项可让编译器为您生成函数。编译器生成的函数可以更有效。
即使我没有编写编译器,我也不会与Stroustrup,Sutter以及他们的几百位朋友和同事争论,因此我无法证明它更有效率。尽可能使用课堂初始化程序。
答案 1 :(得分:5)
我能想到的差异是member initializer list优先于default member initializer。
通过默认的成员初始化程序,它只是一个大括号或 等于使用的成员声明中包含的初始化程序 如果在成员初始化列表中省略了该成员。
如果成员具有默认成员初始值设定项并且也出现在 构造函数中的成员初始化列表,默认成员 初始化程序被忽略。
例如:
class Test
{
public:
Test() {} // count will be 10 since it's omitted in the member initializer list
Test(int c) : count(c) {} // count's value will be c, the default member initializer is ignored.
private:
int count = 10;
};
答案 2 :(得分:4)
在这两种情况下,我们都在讨论member initialization。 请记住,成员是在班级的sequence in which they are declared中初始化的。
在第二个版本中:
Test() : count(10) {
: count(10)
是构造函数初始值设定项(ctor-initializer),count(10)
是成员初始值设定项,是成员初始值设定项列表的一部分。我喜欢将此视为真实的&#39;或初始化发生的主要方式,但它不确定初始化的顺序。
在第一个版本中:
private:
int count=10;
count
有一个默认成员intitializer 。这是后备选项。如果构造函数中不存在成员初始值设定项,它将用作成员初始值设定项,但在类中,将确定初始化成员序列。
从标准的 12.6.2初始化基础和成员,第10项部分开始:
如果给定的非静态数据成员同时具有 brace-or-equal-initializer和mem-initializer,初始化 由mem-initializer指定执行,以及非静态数据 member的brace-or-equal-initializer被忽略。 [例子:给定
struct A { int i = / some integer expression with side effects / ; A(int arg) : i(arg) { } // ... };
A(int)构造函数只需将i初始化为arg的值, 并且i的支撑或平衡初始化器中的副作用不会采取 地点。 - 例子]
要记住的其他事情是,如果你引入一个非静态数据成员初始值设定项,那么结构将不再被认为是C ++ 11中的聚合,但这已经是updated for C++14。
使用一种形式而不是另一种形式的差异(如果 有)。
答案 3 :(得分:2)
代码没有区别。如果您将有多个构造函数重载并且多个计数将是10,那么差异就会出现。对于第一个版本,您将需要更少的写入。
class Test
{
public:
Test() = default;
Test(int b) : b(b) {} // a = 1, c = 3
~Test();
private:
int a = 1;
int b = 2;
int c = 3;
};
与第二个版本相反,上面的代码如下所示:
class Test
{
public:
Test() : a(1), b(2), c(3) {}
Test(int b) : a(1), b(b), c(3) {}
~Test();
private:
int a;
int b;
int c;
};
随着更多成员变量,差异越大。
答案 4 :(得分:1)
当你在成员的声明旁边初始化时,这仅在C ++ 11以后才有效,所以如果你在C ++ 98/03中,你就完全不能这样做。
如果值永远不会改变,您可以选择将其改为constexpr static
,然后编译器将被要求不为该值使用任何额外的存储空间(只要您不定义它)并且无论在何处使用该值,都可以立即使用常量传播。
使用by-declaration语法的一个缺点是它必须位于标头中,这将导致每次要更改其值时重新编译包含标头的所有翻译单元。如果这需要很长时间,那可能是不可接受的。
另一个区别是使用成员初始化列表允许您更改每个构造函数的值,而使用by-declaration版本只允许您为所有构造函数指定一个值(尽管您可以覆盖此值...但是我和#39; d个人避免这种情况,因为它可能会让人感到困惑!)。
顺便说一句,此处无需使用new
来创建Test
的实例。当人们从其他语言中学习语言并且我想让你知道时,这是一个常见的错误。在您的示例之外,当然有许多用途。