当我碰到这个问题时,我正在浏览构造函数初始化列表中的一些问题。
考虑一下:
class Student {
public:
Student() {
id = 0;
}
Student(int i) {
id = i;
}
private:
int id;
};
现在,看看这个:
当你进入构造函数的主体时,所有字段都已构建;如果他们有默认的构造函数,那些已经被调用。现在,如果在构造函数的主体中为它们赋值,则调用复制构造函数。这是低效的,因为两个构造函数最终被调用而不是一个。
来源:What does a colon following a C++ constructor name do?
那么,这是否意味着当我调用无参数构造函数时,也会调用复制构造函数?
请解释一下。这真令人困惑。
特别是第一行的含义:
当你进入构造函数的主体时,所有字段都已构造
答案 0 :(得分:4)
这意味着int id
在您到达id = 0
行之前已经初始化了。由于未指定显式初始值设定项,因此已对其进行了默认初始化。另外,因为它是int
,初始化规则会告诉我们它会有一些不确定的值。
在实践中,对于int
或任何初始化非常便宜的类型,这并不重要。
如果不使用int
成员,我们使用了一个类,我们可以更清楚地看到幕后实际发生的事情:
#include <iostream>
class Verbose {
public:
Verbose() {
std::cout << __PRETTY_FUNCTION__ << "\n";
}
Verbose(int) {
std::cout << __PRETTY_FUNCTION__ << "\n";
}
Verbose(Verbose const &) {
std::cout << __PRETTY_FUNCTION__ << "\n";
}
Verbose & operator=(Verbose const &) {
std::cout << __PRETTY_FUNCTION__ << "\n";
return *this;
}
~Verbose() {
std::cout << __PRETTY_FUNCTION__ << "\n";
}
};
class Object {
public:
Verbose v;
Object() {
v = Verbose(3);
}
};
int main() {
Object o;
}
此代码将输出:
Verbose::Verbose()
Verbose::Verbose(int)
Verbose &Verbose::operator=(const Verbose &)
Verbose::~Verbose()
Verbose::~Verbose()
请注意我们:
v
。Verbose(3)
Object o
超出范围时,我们会销毁成员变量。请注意,我们基本上构建了Verbose v
两次!我们首先使用默认构造函数,然后我们基本上使用operator=
调用重建它。如果我们使用initializer list,我们可以将其减少到一次调用Verbose(int)
。
答案 1 :(得分:3)
他们的意思是
Student() {
id = 0;
}
效率低于
Student() : id(0) {}
在此特定示例中,id
将在一个步骤中初始化,因为该成员只是int
。
相比之下,如果Student
具有更复杂的成员,如Backpack
和Books
,则后一种方法会有所不同。如果这些类不是POD,第一种方法将采用两个步骤来初始化成员,第二种方法只需要一步来初始化。