C++ is on the way 8: 类初始化列表的分析总结

Author:gnuhpc
WebSite:blog.csdn.net/gnuhpc

1.在子类构造时完成父类(没有默认构造函数)的初始化参数传入:

 
#include <iostream>
class Foo
{
        public:
        Foo( int x ) 
        {
                std::cout << "Foo's constructor " 
                          << "called with " 
                          << x 
                          << std::endl; 
        }
};
 
class Bar : public Foo
{
        public:
        Bar() : Foo( 10 )  // construct the Foo part of Bar
        { 
                std::cout << "Bar's constructor" << std::endl; 
        }
};
 
int main()
{
        Bar stool;
}

2.初始化const成员和reference成员

 
#include <iostream>
using namespace std;
 
class const_field
{
        public:
                const_field(int ii) : _constant( 1 ),ref( i ) { i=ii; }
                int geti(){return i;}
                int getref(){return ref;}
 
        private:
                const int _constant;
                int &ref;
                int i;
};
 
 
int main()
{
        const_field cos(100);
        cout << cos.geti() <<" " << cos.getref()<<endl;
}
 

注:初始化列表在构造函数函数体运行之前完成,在构造函数函数体运行中,数据成员的设置是赋值,而不是初始化。初始化阶段可以是显式或隐式的,这要取决于类成员的类型,对于built-in成员其实都一样,但是对于类成员,是否存在成员初始化表则有所不同:若不存在则是隐式初始化,按照声明的顺序依次调用所有类成员函数所属基类的默认构造函数(见后边的练习),在函数体内有赋值动作调用赋值构造函数。若存在则属于显式初始化,类成员使用复制构造函数完成初始化,这也就是我们有时会说在初始化列表中初始化开销会小些的原因(因为若在函数体内再赋值,那么类成员函数的默认构造函数执行所做的工作都是无用功),例如:

Account(){

_name = “”:

_balance=0.0;

}

这里面的string型的_name在赋值前已经被初始化阶段隐式初始为空串(调用了string的默认构造函数),所以在函数体中的赋值是完全没有意义的。

总之,建议使用初始化列表(注意是按照成员声明顺序,而不是列表顺序)来做对象创建时初始化工作。

初始化顺序为:

  1. 基类
  2. 成员数据成员(初始化列表)
  3. 构造函数函数体

附:练习

 
#include <iostream>
using namespace std;
 
class Test
{
public:
 Test()
 {
  ctor_count++;
  cout<<"ctor "<<ctor_count<<endl;
 }
 Test(const Test & r)
 {
  ctor_count++;
  cout<<"copy ctor "<<ctor_count<<endl;
 }
 Test & operator= (const Test& r)
 {
  ctor_count++;
  cout<<"assignment op "<<ctor_count<<endl;
  return *this;
 }
private:
 static int ctor_count; //only a declaration
};
int Test::ctor_count=0; // definition + initialization
 
class Task
{
private:
 int pid;
 Test name; // type changed from string to Test
public:
 Task (int num, const Test & n) {pid=num; name=n;}
};
 
int main(void)
{
 Test t;
 Task task(1, t);
 return 0;
}
 

运行结果:

 
[root@localhost ~]# ./a.out
ctor 1
ctor 2
assignment op 3
 

解释:static int是为了更好的说明问题,不要被这个类型所迷惑。第一行表示程序在构造t。第二行表示默认初始化时调用默认构造函数,第三行是构造task时的赋值。

将程序的初始化修改:

Task (int num, const Test & n):pid(num),name(n) {}

运行结果是:

ctor 1
copy ctor 2

下边的这个程序也可以说明问题,如果还不理解上例的话:

 
#include <iostream>
using namespace std;
 
class Bar
{
public:
  Bar();
  Bar(int x);
  Bar & operator=(const Bar& bar)
  {
      cout <<"Assignment Bar constructed." <<endl;
  }
 
  Bar(const Bar &bar)
  {
      cout <<"Copy Bar constructed." <<endl;
  }
private:
  int x;
};
 
Bar::Bar()
{
  std::cout << "Bar default-constructed." << std::endl;
}
 
Bar::Bar(int x) : x(x)
{
  std::cout << "Bar constructed." << std::endl;
}
 
 
class Foo
{
public:
  Foo(Bar bar);
private:
  Bar bar;
};
 
Foo::Foo(Bar bar)
{
  this->bar = bar;
}
 
//Foo::Foo(Bar bar):bar(bar){}
 
int main()
{
    Foo foo(Bar(3));
 
    return 0;
}

                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值