Sphere() : theRadius(1.0)
{
}
为什么使用初始化器(上面)编写构造函数比初始化其体内数据成员的构造函数(下图)更好?
Sphere()
{
theRadius = 1.0;
}
答案 0 :(得分:14)
在进入构造函数体之前初始化所有成员。如果你没有在init列表中提供初始化器,那么它们是默认构造的。
在您的第一个示例中,会发生以下情况:
theRadius
初始化为1.0 在您的第二个示例中,会发生以下情况:
theRadius
已初始化theRadius
对于像int和floats这样的简单类型,这并不重要。但是,如果您的成员是具有非平凡构造函数/复制构造函数的对象,那么使用初始化列表方法会更有效。
答案 1 :(得分:8)
如果没有显式初始化字段,编译器将尝试运行它们的默认构造函数。如果他们没有可访问的默认构造函数,则源代码将无法编译:
class Field {
public:
Field(int x) {}
};
class Test {
Field f;
public:
Test() { // compiler error here. `Field` doesn't have default constructor.
f = Field(10);
}
};
int main ( ) {
Test t;
}
如果他们确实有默认构造函数,那么当你调用正文中字段的另一个构造函数时,你会不必要地调用它。
答案 2 :(得分:3)
在进入构造函数体之前,构造函数总是为对象属性调用。
如果您没有自己指定构造函数,则会调用默认构造函数,稍后将使用operator=
来更改值。
这可能不是你想要的。
特别是,您无法更改构造函数体内的const
属性的值。
你必须使用init列表。
答案 3 :(得分:2)
因为否则会调用对象的默认构造函数,然后设置该值。
这只会调用字符串构造函数
class Foo{
std::string s;
Foo() : s("Hello World"){}
}
这就是:
class Foo{
std::string s;
Foo(){
s = "Hello World";
}
}
将调用默认字符串构造函数,然后将字符串的值设置为“Hello World”
答案 4 :(得分:1)
如前所述,对于非原始类型,它会有所不同。
这也是初始化const成员变量的唯一方法。
class MyClass
{
const int x;
public:
MyClass(int x)
{
this->x=x;
}
};
这不应该编译。
答案 5 :(得分:1)
就像其他人所说的那样,使用第一种形式进行非平凡构造的类型效率更高。
此外,第一种形式使您能够捕获通过使用try / catch块的函数形式初始化的成员对象(或基类)的构造函数中抛出的任何异常。 e.g:
MyObject() : memberObject(...)
try {
// my constructor
}
catch (...) {
// catches exceptions in try block AND memberObject constructor
}
这并没有错过一组括号。如果你在try / catch块周围放置了另一组括号,它将不会捕获memberObject构造函数中的异常,只会捕获try块。
答案 6 :(得分:1)
它主要用于初始化常量和引用变量,因为它们无法在构造函数体中初始化。