C++在类的构造函数中,可以两种方式初始化成员数据:
- 在构造函数的实现中,初始类的成员数据。
- 还可以定义初始化成员列表 (Initializer list) 来初始化成员数据。
那么我们在什么情况下该使用初始化成员列表呢?
- 需要初始化的数据成员是对象。
- 需要初始化的类成员是const对象或者引用对象。
- 解决没有默认构造函数的类成员对象的生成。
- 在继承里面,只有初始化列表可以构造父类的private成员。
1. 需要初始化的数据成员是对象。
- #include <stdio.h>
- class point
- {
- protected:
- int m_x,m_y;
- public:
- point(int m=0,int n=0)
- {
- m_x = m;
- m_y = n;
- printf("constructor called!\n");
- }
- point(point& p)
- {
- m_x = p.GetX();
- m_y = p.GetY();
- printf("copy constructor called!\n");
- }
- int GetX()
- {
- return m_x;
- }
- int GetY()
- {
- return m_y;
- }
- };
- class point3d
- {
- private:
- point m_p;
- int m_z;
- public:
- point3d(point p, int k)
- {
- m_p = p;
- m_z=k;
- }
- point3d(int i,int j, int k):m_p(i,j) // 相当于 point m_p(i,j)这样对m_p初始化
- {
- m_z=k;
- }
- void Print()
- {
- printf("%d,%d,%d \n",m_p.GetX(),m_p.GetY(),m_z);
- }
- };
我们可以使用如下进行初始化,它将调用拷贝构造函数:
关于拷贝构造函数,可参见 http://www.cnblogs.com/BlueTzar/articles/1223313.html
- void main()
- {
- point p1(1,2); //先定义一个2D坐标
- point3d p3d(p1,3);
- p3d.Print();
- }
输出:
constructor called!
copy constructor called!
constructor called!
1,2,3
为什么呢?
第一个constructor called!是构造p1;
第二个copy constructor called!是把p1传入函数p3d的p时,因为函数形参的赋值操作时一个使用拷贝构造函数的过程。会调用拷贝构造函数把p1拷贝到p;
第三个constructor called!是point3d p3d(p,3)这个构造函数执行时,首先按顺序初始化所有的成员列表,然后执行函数体。初始化列表时,虽然我们没有显示的告诉它怎么初始化,但是此时编译器会用默认值进行初始化,一般是0。对于其中的成员变量m_p,会采用默认的无参数构造函数。(如果没有默认的无参构造函数,此时编译会报错,解决方法是,在初始化列表里显示的使用有参构造)至于m_p=p这个怎么运行呢,这里不会调用拷贝构造函数,因为拷贝构造函数也是一种构造函数,只有在心间对象时会调用,此处调用的是=号运算符,如果我们没有定义这个运算符操作,则编译器会自己合成一个按位拷贝的=号操作运算函数。
也可以使用初始化成员列表进行初始化:
- void main()
- {
- point3d p3d(1,2,3);
- p3d.Print();
- }
输出:
constructor called!
1,2,3
只调用了一次constructor called!,这次调用是在上面那种里的第三个constructor called!,构造成员变量m_p,在初始化列表里,使用含参构造
由于对象赋值比初始化要麻烦的多,因此也带来的性能上的消耗。所以使用初始化列表可以更高效地初始化成员变量是对象的情况。
2. 需要初始化的类成员是const对象或者引用对象。
对于类成员是const修饰,或是引用类型的情况,是不允许赋值操作的,、因此只能用初始化列表对其进行初始化。
- #include <stdio.h>
- class base
- {
- private:
- const int a;
- int& b;
- public:
- // base(int m, int n)
- // {
- // a = m;
- // b = n;
- // }
- base(int m, int n):a(m),b(n)
- {}
- };
- void main()
- {
- base b(1,2);
- }
其中,注释的部分将无法通过编译。
3. 解决没有默认构造函数的类成员对象的生成。
如果成员类型是没有默认构造函数的类。若没有提供显示初始化,则编译器隐式使用成员类型的默认构造函数,若该类没有默认构造函数,则编译器尝试使用默认构造函数将会失败。
4. 在继承里面,只有初始化列表可以构造父类的private成员。
原文地址:http://blog.csdn.net/freedom0203/article/details/2805945