在C++中,如果类成员变量在构造函数体内进行赋值,而不是使用初始化列表,那么该成员变量不会调用两次构造函数。具体来说,它的行为如下:
1. 成员变量的初始化过程
-
当创建一个类的对象时,所有成员变量会首先进行默认初始化。
-
如果成员变量是类类型(例如另一个类的对象),则会调用其默认构造函数。
-
如果成员变量是基本类型(如
int
、double
等),则不会进行初始化(值未定义)。
-
-
然后,如果成员变量在构造函数体内被赋值,会调用其赋值运算符(
operator=
),而不是构造函数。
2. 示例分析
以下是一个示例:
#include <iostream> class SubObject { public: SubObject() { std::cout << "SubObject Default Constructor\n"; } SubObject(int value) { std::cout << "SubObject Parameterized Constructor\n"; } SubObject& operator=(int value) { std::cout << "SubObject Assignment Operator\n"; return *this; } }; class MyClass { public: SubObject obj; MyClass(int value) { obj = value; // 赋值操作 } }; int main() { MyClass myObj(10); return 0; }
输出结果:
SubObject Default Constructor SubObject Assignment Operator
解释:
-
在创建
MyClass
对象时,成员变量obj
首先会调用SubObject
的默认构造函数。 -
然后,在构造函数体内执行
obj = value;
时,会调用SubObject
的赋值运算符(operator=
),而不是再次调用构造函数。
3. 使用初始化列表的情况
如果使用初始化列表,成员变量会直接调用匹配的构造函数,而不会先调用默认构造函数再赋值。
class MyClass { public: SubObject obj; MyClass(int value) : obj(value) { // 使用初始化列表 } };
输出结果:
SubObject Parameterized Constructor
解释:
-
成员变量
obj
直接调用SubObject(int value)
构造函数,避免了默认构造和赋值的额外开销。
4. 总结
-
在构造函数体内赋值时:
-
成员变量会先调用默认构造函数(如果是类类型)。
-
然后调用赋值运算符(
operator=
)。
-
-
使用初始化列表时:
-
成员变量会直接调用匹配的构造函数,效率更高。
-
因此,成员变量不会调用两次构造函数,但会调用一次构造函数和一次赋值运算符。为了优化性能,推荐使用初始化列表来初始化成员变量,尤其是对于类类型的成员变量。