成员初始化表

    技术2022-07-06  188

    三种情况下需要使用初始化成员列表         1)对象成员;         2)const修饰的成员;         3)引用成员数据;

    1.对于非类数据成员的初始化或赋值,除了两个例外,两者在结果和性能上都是等价的。 两个例外是指任何类型的const和引用数据成员。const 和引用数据成员也必须是在成员初始化表中被初始化 否则 就会产生编译时刻错误。

    例如 下列构造函数的实现将导致编译 时刻错误:

    class ConstRef { public:  ConstRef( int ii );   private:  int i;  const int ci;  int &ri; };   ConstRef:: ConstRef( int ii ) { // 赋值  i = ii; // ok  ci = ii; // 错误: 不能给一个 const 赋值  ri = i; // 错误  ri 没有被初始化 } 当构造函数体开始执行时 所有const 和引用的初始化必须都已经发生。因此 只有将它 们在成员初始化表中指定这才有可能 正确的实现如下:

    // ok: 初始化引用和 const ConstRef:: ConstRef( int ii )  : ci( ii ), ri( i )  { i = ii; }

     

    2.     每个成员在成员初始化表中只能出现一次 初始化的顺序不是由名字在初始化表中的顺序决定 而是由成员在类中被声明的顺序决定的. 例如, 给出下面的 Account 数据成员的声明顺序 :

    class Account { public:  // ... private:  unsigned int _acct_nmbr;  double _balance;  string _name; };

    下面的缺省构造函数  inline Account:: Account() : _name( string() ), _balance( 0.0 ), _acct_nmbr( 0 )  {}

         的初始化顺序为 acct_nmbr _balance 然后是_name.但是在初始化表中出现(或者在被隐式初始化的成员类对象中) 的成员,总是在构造函数体内成员的赋值之前被初始化. 例 如 在下面的构造函数中  inline Account:: Account( const char *name, double bal )  : _name( name ), _balance( bal ) {  _acct_nmbr = get_unique_acct_nmbr(); }      初始化的顺序是_balance _name 然后是_acct_nmbr       由于这种 实际的初始化顺序 与 初始化表内的顺序 之间的明显不一致,有可能导致以下难于发现的错误,当用一个类成员初始化另一个时:

    class X {  int i;  int j; public:  // 喔! 你看到问题了吗?  X( int val )   : j( val ), i( j )   {}  // ... };

     

    尽管看起来 j 好像是用 val 初始化的 而且发生在它被用来初始化i 之前 但实际上是i 先被初始化的, 因此它是用一个还没有被初始化的 j 初始化的 我们的建议是 把“用一个成员对另一个成员进行初始化 如果你真的认为有必要” 的代码放到构造函数体内, 如下所示  :

    // 更好的习惯用法 X::X( int val ) : i( val ) { j = i; }

     

    --------摘自《C++ Primer》

     

    看下面的代码:

    class A { public:     A();     A(int aValue);     A(const A& aObject);     A& operator=(const A& aObject); private:     int iValue; }; A::A() {     cout << "default construct function is called" << endl; } A::A(int aValue) {     iValue = aValue;     cout << "construct function is called" << endl; } A::A(const A& aObject) {     this->iValue = aObject.iValue;     cout << "copy construct function is called" << endl; } A& A::operator =(const A &a) {     this->iValue = a.iValue;     cout << "copy assignment function is called" << endl;     return *this; } class B { public:     B(int aValue); private:     int iValue;     A a; }; B::B(int aValue) {     a = 5; } class C { public:     C(int aValue); private:     int iValue;     A a; };

     

    C::C(int aValue):a(5) {     cout << "construct function of the C object is called" << endl; }

     

     

    int main(int argc, char* argv[]) {     B b(5);     cout << "-------------------" << endl;     C c(5);     delete p;     delete pp;     return 0; }

     

    程序会输出:

    default construct function is called

    construct function is called

    copy assignment function is called

    -------------------

    construct function is called

    construct function of the C object is called

     

    从上面可以看出隐式初始化的调用明显比成员初始化繁琐的多。


    最新回复(0)