C++ 为什么我更喜欢使用成员初始化列表?
我喜欢在构造函数中使用成员初始化列表。。。但我早就忘记了这背后的原因 在构造函数中是否使用成员初始化列表?若然,原因为何?若否,原因为何 对于班级成员来说,这没什么区别,只是风格的问题。对于属于类的类成员,它避免了对默认构造函数的不必要调用。考虑:C++ 为什么我更喜欢使用成员初始化列表?,c++,oop,object-construction,C++,Oop,Object Construction,我喜欢在构造函数中使用成员初始化列表。。。但我早就忘记了这背后的原因 在构造函数中是否使用成员初始化列表?若然,原因为何?若否,原因为何 对于班级成员来说,这没什么区别,只是风格的问题。对于属于类的类成员,它避免了对默认构造函数的不必要调用。考虑: class A { public: A() { x = 0; } A(int x_) { x = x_; } int x; }; class B { public: B() { a.x = 3
class A
{
public:
A() { x = 0; }
A(int x_) { x = x_; }
int x;
};
class B
{
public:
B()
{
a.x = 3;
}
private:
A a;
};
在这种情况下,B
的构造函数将调用A
的默认构造函数,然后将A.x
初始化为3。更好的方法是B
的构造函数直接调用初始值设定项列表中A
的构造函数:
B()
: a(3)
{
}
class A
{
public:
A(int x_) { x = x_; }
int x;
};
class B
{
public:
B() : a(3), y(2) // 'a' and 'y' MUST be initialized in an initializer list;
{ // it is an error not to do so
}
private:
A a;
const int y;
};
这将只调用A
的A(int)
构造函数,而不是其默认构造函数。在本例中,差异可以忽略不计,但是想象一下,如果您愿意的话,A
的默认构造函数做的更多,例如分配内存或打开文件。你不会不必要地这么做的
此外,如果类没有默认构造函数,或者您有const
成员变量,则必须使用初始值设定项列表:
B()
: a(3)
{
}
class A
{
public:
A(int x_) { x = x_; }
int x;
};
class B
{
public:
B() : a(3), y(2) // 'a' and 'y' MUST be initialized in an initializer list;
{ // it is an error not to do so
}
private:
A a;
const int y;
};
除了上面提到的性能原因外,如果您的类存储对作为构造函数参数传递的对象的引用,或者您的类具有常量变量,则除了使用初始值设定项列表之外,您别无选择。在性能问题旁边,还有一个非常重要的问题,我称之为代码可维护性和可扩展性 如果
T
是POD,并且您开始首选初始化列表,那么如果有一次T
将更改为非POD类型,您不需要更改初始化周围的任何内容,以避免不必要的构造函数调用,因为它已经过优化
如果typeT
确实有默认构造函数和一个或多个用户定义的构造函数,并且有一次您决定删除或隐藏默认构造函数,那么如果使用了初始化列表,则不需要更新用户定义的构造函数的代码,因为它们已经正确实现
与const
成员或引用成员相同,假设最初T
的定义如下:
struct T
{
T() { a = 5; }
private:
int a;
};
接下来,您决定将a
限定为const
,如果您从一开始就使用初始化列表,那么这是一个单行更改,但是如果将T
定义为如上所述,还需要挖掘构造函数定义以删除赋值:
struct T
{
T() : a(5) {} // 2. that requires changes here too
private:
const int a; // 1. one line change
};
如果代码不是由一个“代码猴子”编写的,而是由一个工程师编写的,并且该工程师基于对自己所做工作的更深入考虑做出决策,那么维护就容易得多,也不容易出错,这已不是什么秘密。在运行构造函数主体之前,调用其父类的所有构造函数,然后调用其字段的所有构造函数。默认情况下,将调用无参数构造函数。初始化列表允许您选择调用哪个构造函数以及构造函数接收哪些参数 如果有引用或常量字段,或者所使用的某个类没有默认构造函数,则必须使用初始化列表
// Without Initializer List
class MyClass {
Type variable;
public:
MyClass(Type a) { // Assume that Type is an already
// declared class and it has appropriate
// constructors and operators
variable = a;
}
};
在这里,编译器按照以下步骤创建类型为MyClass
的对象:
Type
的构造函数首先为“a
”调用MyClass()
构造函数的主体内调用“Type
”的赋值运算符进行赋值Type
”的析构函数被“a
”调用,因为它超出了范围现在考虑与<代码> MyCype()< /C>构造函数相同的代码:初始化列表:
// With Initializer List
class MyClass {
Type variable;
public:
MyClass(Type a):variable(a) { // Assume that Type is an already
// declared class and it has appropriate
// constructors and operators
}
};
对于初始值设定项列表,编译器遵循以下步骤:
Type
”类的复制构造函数来初始化:变量(a)
。初始值设定项列表中的参数用于直接复制构造“变量”
”
类型
”的析构函数被“a
”调用,因为它超出了范围
class Sample
{
public:
int Sam_x;
int Sam_y;
Sample(): Sam_x(1), Sam_y(2) /* Classname: Initialization List */
{
// Constructor body
}
};
需要初始化列表:
class Sample
{
public:
int Sam_x;
int Sam_y;
Sample() */* Object and variables are created - i.e.:declaration of variables */*
{ // Constructor body starts
Sam_x = 1; */* Defining a value to the variable */*
Sam_y = 2;
} // Constructor body ends
};
在上面的程序中,当类的构造函数被执行时,Sam_x和Sam_y是c
1. Default constructor of Sample1 class
2. Initialization list in Sample2 class which will call the parametric constructor of Sample1 class (as per above program)
class Sample3 {
int i; /* Member variable name : i */
public:
Sample3 (int i) /* Local variable name : i */
{
i = i;
print(i); /* Local variable: Prints the correct value which we passed in constructor */
}
int getI() const
{
print(i); /*global variable: Garbage value is assigned to i. the expected value should be which we passed in constructor*/
return i;
}
};
1. Initialization list
2. this operator.
class NumArray {
public:
vector<int> preSum;
NumArray(vector<int> nums) {
preSum = vector<int>(nums.size()+1, 0);
int ps = 0;
for (int i = 0; i < nums.size(); i++)
{
ps += nums[i];
preSum[i+1] = ps;
}
}
int sumRange(int i, int j) {
return preSum[j+1] - preSum[i];
}
};
class NumArray {
public:
vector<int> preSum;
NumArray(vector<int> nums) : preSum(nums.size()+1, 0) {
int ps = 0;
for (int i = 0; i < nums.size(); i++)
{
ps += nums[i];
preSum[i+1] = ps;
}
}
int sumRange(int i, int j) {
return preSum[j+1] - preSum[i];
}
};