C++成员初始化列表

我们知道在C++里,对象的构造是由构造函数完成的,一般的我们会在构造函数体内完成成员的初始化工作,像下面这样: 

class X
{
    public:
        X(int val) {i =val;j=i;}
    public:
        int i;
        int j;
}

这是比较简单的一种情况,因为它没有涉及到有虚函数以及继承链里有虚基类的情况,在有虚函数的情况一下,一般是编译器会在构造函数中(由编译器合成或者是开发着提供)安插vptr指针,并妥当的设置好它的值,使得它指向该类的虚函数表,虚函数表也是在编译期间完成的,这里不再细说。

构造函数的另外一种语法就是本文的主题:成员初始化列表。像下面这样:

class X
{
    public:
        X(int val):i(val),j(i){}
    public:
        int i;
        int j;
}

成员初始化列表并不是一种函数调用,初始化成员的次序非常讲究,编译器真正初始化成员的顺序是按照它们在类中申明的次序的,而并不是列在成员初始化列表里的顺序,上面的示例中的初始化没有任何问题,咱们再来看一种情况,你会得到一个怪异的结果。

class X
{
    public:
        X(int val):j(val),i(j){}
    public:
        int i;
        int j;
}

看出区别了吗?成员初始化列表里面的次序发生了变化,我们来简单的测试一下到底有什么不同。

#include <iostream>
 
using std::cout;
using std::endl;
 
class X
{
     public:
         X(int val):i(val),j(i){}
     public:
         int i;
         int j;
};

int main()
{   
     X x(100);
     
     cout << x.i << endl << x.j << endl;
     
     return 0;
}

输出:
100
100

没有任何问题,再来看上面的后一种情况。

#include <iostream>
 
using std::cout;
using std::endl;
 
class X
{
     public:
         X(int val):j(val),i(j){}
     public:
         int i;
         int j;
};

int main()
{   
     X x(100);
     
     cout << x.i << endl << x.j << endl;
     
     return 0;
}

输出:
10653684
100

显然不是我们要的结果,对不对?这是因为,编译器是按照申明次序来进行初始化的,所以先初始化i,这时候j是未初始化过的,因此得到的时候脏数据。gcc/g++编译器能对这种情况给出警告,像下面这样

g++ -c -Wall -O3 hello.cpp -o hello.o
hello.cpp: In constructor `X::X(int)':
hello.cpp:12: warning: `X::j' will be initialized after
hello.cpp:11: warning:   `int X::i'
hello.cpp:9: warning:   when initialized here
g++ -o hello hello.o 

如果没有对成员初始化列表这样的理解,估计大家对这样的警告有所不理解,另外,下面这四种情况下是必须要用成员初始化列表语法来初始化成员的:

1.初始化一个reference member
2.初始化一个const member
3.调用一个base class的构造函数,而它拥有一组参数
4.调用一个member class的构造函数,而它拥有一组参数

最后一点,当成员都是基本类型时,两种构造方法在效率上没有任何区别,当成员有class对象时,情况就不一样,在构造函数体中通过赋值运算符=进行初始化时,会产生临时对象,在用成员初始化列表进行构造时,会直接调用class 成员的copy 构造函数,效率上会有所提升,不过现在的编译器将做何种优化也视不同的编译器而异。举个例子:


class Word
{
	public;
		Word(){name=0;cnt=0;}
	public:
		string name;
		int cnt;
}

编译器对构造函数可能做的扩张如下:

Word::Word()
{
	name.string::String();
	string temp = string(0);
	name.string::operator=(temp);
	temp.string::~string();
	cnt=0
}

继续

class Word
{
	public:
		Word():name(0)
		{cnt=0;}
	public:
		string name;
		int cnt;
}

编译器对构造函数可能做的扩张如下:

Word::Word()
{
	name.string::string(0);
	cnt = 0;
}

完。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值