C++中重载构造函数的互相调⽤初始化成员变量的问题
⽂章⽬录
C++中重载的互相调⽤初始化成员变量的问题
写⼀个类的时候,我们可能会希望有多重不同的初始化⽅式,此时就⽤到了重载构造函数。例如:
这样我们可以有两种⽅式来初始化⼀个TestConstructor对象。
两个重载构造函数实现的代码可以分别是:
不能直接互相调⽤的重载构造函数
对于上边的这个⽆参构造函数,我们可以直接初始化value为10,但是如果参数很多,重载构造函数很多,那么就不可能每个都写⼀遍⼀模⼀样的赋值操作(其实也可以,就是有些丑,⽽且如果发⽣改动,则有可能会因为疏忽⽽出错)。所以,我们希望能够减少重复的赋值操作,例如调⽤其他的重载构造函数,就像这样,
但是这样可以嘛?我们试⼀下,为了⽅便查看实际⽣成的对象,我们在构造函数⾥输出对象的指针地址。class  TestConstructor {public : int  value ;public : TestConstructor (); TestConstructor (int );};
1
2
3
4
5
6
7
8
9TestConstructor ::TestConstructor (){ this ->value = 10;}      TestConstructor ::TestConstructor (int  value ){ this ->value = value ;}
1
2
3
4
5
6
78
9TestConstructor ::TestConstructor (){ TestConstructor (10);}TestConstructor ::TestConstructor (int  value ){ this ->value = value ;}
1
2
3
4
5
6
7
8
9
运⾏结果:
constructor2:0x7fff81eb3494
constructor1:0x5586774bce70
0x5586774bce70
可以看出,在构造函数中调⽤重载构造函数时,被调⽤的构造函数重新创建了⼀个新的对象,所以不能⽤这种⽅法。
使⽤⼀个的函数初始化成员变量
在我之前的项⽬中,为了解决这个问题,我采⽤了另外写⼀个private的函数的⽅法,把⼀些需要反复初始化的部分扔进了⼀个private的函数⾥。例如,#include  <iostream>using  namespace  std ;class  TestConstructor {public : int  value ;public : TestConstructor (); TestConstructor (int );};TestConstructor ::TestConstructor (){ TestConstructor (10); cout << "constructor1:" << this  << endl ;}TestConstructor ::TestConstructor (int  value ){ this ->value = value ; cout << "constructor2:" << this  << endl ;}int  main (){ TestConstructor *t = new  TestConstructor (); cout << t ->value << endl ; cout << t << endl ; delete  t ; return  0;}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
这个当然是⼀种解决⽅案。不过,最近⽤cppcheck analysis的时候,总是提⽰我 Member variable "xxx" is not initialized in the constructor.,这促使我思考了⼀下是否有更好的⽅法解决该问题。
使⽤带有默认参数的构造函数
在C++的函数声明中可以设置默认参数,所以⼀种可⾏的⽅法就是⽤含默认参数的构造函数来代替重载构造函数。如:
(NOTE:注意默认参数通常放在函数声明上,并且只能写⼀次,即声明写了,定义部分就不能再写)
使⽤placement new 调⽤重载构造函数
C++提供在预先分配好的内存上创建对象的⽅法,即placement new运算符。在C++中,构造函数的执⾏实际上分为两个阶段,分别是初始化阶段和计算阶段,其中初始化阶段先于计算阶段。在进⼊计算阶段前,所有的成员变量都已经完成了初始化,所以内存也都已经按需分配好,此时我们可以在this指针指向的这块内存上调⽤重载构造函数创建⼀个新的对象,覆盖掉原来的对象。class  TestConstructor {private : void  initialize (int );public : int  value ;public : TestConstructor (); TestConstructor (int );};void  TestConstructor ::initialize (int  value ){ this ->value = value ;}TestConstructor ::TestConstructor (){ this ->initialize (10); cout << "constructor1:" << this  << endl ;}TestConstructor ::TestConstructor (int  value ){ this ->initialize (value ); cout << "constructor2:" << this  << endl ;}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
构造函数可以被重载
19
20
21
22
23
24
25
26
27
28
29class  TestConstructor {public : int  value ;public : TestConstructor (int  value = 10);};TestConstructor ::TestConstructor (int  value ){ this ->value = value ;}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
运⾏结果:
constructor2:0x55bece811e70
constructor1:0x55bece811e70
10
0x55bece811e70
使⽤C++11的委托构造函数(在初始化列表位置调⽤)
据我了解这是C++11中加⼊的功能,名为委托构造函数。其将重载构造函数放置在初始化列表的位置调⽤。class  TestConstructor {public : int  value ;public : TestConstructor (); TestConstructor (int  value );};TestConstructor ::TestConstructor (){ new  (this )TestConstructor (10); cout << "constructor1:" << this  << endl ;}TestConstructor ::TestConstructor (int  value ){ this ->value = value ; cout << "constructor2:" << this  << endl ;}int  main (){ TestConstructor *t = new  TestConstructor (); cout << t ->value << endl ; cout << t << endl ; delete  t ; return  0;}
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
运⾏结果:
constructor2:0x5594d644de70
constructor1:0x5594d644de70
10
0x5594d644de70
##总结
对于重载构造函数的互相调⽤初始化成员变量的问题,我们可以
1. 使⽤⼀个私有函数初始化成员变量
2. 使⽤带有默认参数的构造函数
3. 使⽤placement new运算符调⽤重载构造函数
4. 使⽤C++11的委托构造函数(在初始化列表位置调⽤)class  TestConstructor {public : int  value ;public : TestConstructor (); TestConstructor (int );};TestConstructor ::TestConstructor ():TestConstructor (10){ cout <<"constructor1:"<< this  << endl ;}      TestConstructor ::TestConstructor (int  value ){ this ->value = value ; cout <<"constructor2:"<<this  << endl ;}int  main (){ TestConstructor *t = new  TestConstructor (); cout << t ->value << endl ; cout << t << endl ; delete  t ; return  0;}
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。