我用C ++编程了一段时间,我使用了两种方法:
class Stuff {
public:
Stuff( int nr ) : n( nr ) { }
private:
int n;
}
或者
class Stuff {
public:
Stuff( int nr ) {
n = nr;
}
private:
int n;
}
注意:这与this不同,相似但不相同。
什么是最佳做法?
答案 0 :(得分:21)
首选项列表是首选。见FAQ 10.6
答案 1 :(得分:12)
使用初始化程序的一大优势:如果在初始化程序列表中的任何位置抛出异常,则将为那些已经初始化的成员调用析构函数 - 并且仅针对那些成员。
当您使用构造函数体初始化对象时,您可以正确处理异常并根据需要展开对象。这通常要难以做到。
答案 2 :(得分:5)
尽可能使用初始化列表。对于int来说,无论哪种方式都没关系,但是对于更复杂的成员对象,你最终会得到被调用对象的默认构造函数,然后是对该对象的赋值,这很可能会结束慢了。
另外,对于const成员或没有默认构造函数的成员,无论如何都必须这样做。
答案 3 :(得分:2)
如果可能,请使用第一个版本。
第一个是使用初始化列表进行初始化,并实际调用成员的构造函数。
第二个是作业。如果n是一个带有默认构造函数的类型,那么它就已经被调用了,然后你将分配给它。如果n没有默认构造函数,则会被迫使用第一种类型。同样,如果n是参考:int &n
。
如果没有成员的构造函数直接将其中一个参数带到构造函数中,那么添加可以为您进行转换的私有静态函数可能是值得的。
答案 4 :(得分:1)
我通常会尝试做初始化列表。首先,这使得您明确表示正在构造函数中初始化代码。 const memebers 有以这种方式初始化。
如果你只是把代码放在构造函数的主体中,那么很可能有人可能决定过来并将其中的一大块移动到非构造函数“setup”例程中。
虽然可以采取过度考虑。我有一个同事喜欢创建具有2页initilizer代码的类,没有构造函数代码,并且可能有2页用于整个类的代码。我觉得这很难读。
答案 5 :(得分:0)
第二个选项不是初始化,而是赋值。对于具有用户定义的默认构造函数的类型,第二个选项将调用默认构造函数,稍后调用赋值运算符(无论是否为用户定义)来赋值。
某些类型不能默认初始化:如果您有一个没有默认构造函数的属性,保持引用(常量或不常量)或具有常量属性,则必须在初始化列表中初始化它们。
可以在初始化列表中对数组进行值初始化,但不能在构造函数体中进行值初始化:
class X {
public:
X() : array() {} // value-initializes the array
// equivalent to:
// X() { for ( int i = 0; i < 10; ++i ) array[i]=0; }
private:
int array[10];
};
对于POD类型,您可以在初始化列表中对它们进行值初始化,但不能在括号内进行初始化:
class X {
public:
X() : pod() {} // value-initializes
// equivalent to (but easier to read and subtly faster as it avoids the copy):
// X() { pod = {}; }
private:
PODType pod;
};
最后,一些类通过使用构造函数来提供功能,这些构造函数在默认构造之后会更复杂(如果可以实现)。
class X
{
public:
X() : v(10) {} // construct a vector of 10 default initialized integers
// equivalent to:
// X() { for ( int i = 0; i < 10; ++i ) v.push_back(0); }
private:
std::vector<int> v;
};
最后,只要它们实际上是等价的,初始化列表在C ++中就更具惯用性。
答案 6 :(得分:0)
我想补充一点,你不需要在Header(.h)上声明初始化列表。它可以在构造函数的实现中完成(这很常见)。
那么:
//Stuff.h
class Stuff {
public:
Stuff( int nr );
private:
int n;
}
//Stuff.cpp
Stuff::Stuff(int nr)
: n(nr)
{
//initalize complex members
}
是合法的,imo集中了重要的字段的初始化。有时我们需要初始化正文中的复杂成员,因此您在.cpp文件中都有初始化列表和复杂的初始化。