我一直在用c ++工作一段时间,但我不确定
之间的区别public : Thing(int _foo, int _bar): member1(_foo), member2(_bar){}
和
public : Thing(int _foo, int _bar){
member1 = _foo;
member2 = _bar;
}
我觉得他们做同样的事情,但这两种语法之间存在实际差异。其中一个比另一个更安全,它们是否以不同方式处理默认参数。
并不完全习惯于第一个例子,所以如果我犯了错误,我道歉。
答案 0 :(得分:57)
如果member1
和member2
是非POD(即非 P lain ,则它们不一样O ld D ata )类型:
public : Thing(int _foo, int _bar){
member1 = _foo;
member2 = _bar;
}
相当于
public : Thing(int _foo, int _bar) : member1(), member2(){
member1 = _foo;
member2 = _bar;
}
因为它们将在构造函数体开始执行之前被初始化,所以基本上两次完成工作。这也意味着,如果这些成员的类型没有默认构造函数,那么您的代码将不编译。
答案 1 :(得分:13)
第一个是推荐的最佳实践,因为它更惯用,并且避免重新初始化具有默认构造函数的类型的字段(即非基本类型)。
当你只在构造函数体内初始化一个成员时,如果可以,编译器会为你生成一个默认的成员初始化语句,所以你最终会加倍地初始化它。在某些情况下,这可能不是什么大问题,但如果构造对象很昂贵,可能会造成严重的性能开销。
但是,没有(n显式定义或生成的)默认构造函数的用户定义类型无法以这种方式初始化,因此会产生编译器错误。 const和引用字段也是如此 - 这些只能在成员初始化列表中显式初始化。
答案 2 :(得分:6)
唯一要添加到Péter Török的答案是初始化列表是初始化对象的const成员的唯一方法,即:
class foo
{
public:
foo(int value)
: myConstValue(value)
{};
foo()
{
myConstValue = 0; // <=== Error! myConstValue is const (RValue), you can't assign!
};
private:
const int myConstValue;
}
答案 3 :(得分:4)
在您的示例代码中,构造函数初始化中的第一个和构造函数体内的赋值。
构造函数初始化列表是执行所有成员初始化的最佳方法,因为它可以提高性能。
class A
{
string name;
public:
A(string myname):name(myname) {}
}
在上面的情况下,编译器不会创建临时对象来进行初始化。但是在以下情况中:
A::A()
{
name = myname;
}
创建一个单独的临时对象,并将此临时对象传递给string
的赋值运算符以分配给name
。然后,临时对象被破坏,效率不高。
注意:必须在构造函数初始化列表中初始化引用或const成员。它们不能在构造函数的主体中“分配”。
答案 4 :(得分:2)
除了其他答案之外,我想提一下构造函数初始化仅用于初始化 成员变量。
class Demo
{
int a;
int b;
public:
Demo(int a,int b):a(a),b(b)
{
}
};
如果我们初始化a和b内部构造函数,它将是自我赋值。
答案 5 :(得分:1)
首先是初始化,使用初始化列表,第二个是默认构造,然后是赋值。第一个至少与第二个一样快,并且优于第二个。