成员初始化表

三种情况下需要使用初始化成员列表
        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

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

猜你喜欢

转载自blog.csdn.net/ice2000feng/article/details/6127463