条款12:尽量使用初始化而不要在构造函数里赋值

1.

先看一个模板类

template<class T>
class NamedPtr
{
 public:
  NamedPtr(const string& initName,T* initPtr);
  friend ostream& operator<<(ostream &os,NamedPtr<T> co);
 private:
   string name;
   T*  ptr;//类类型指针成员
};

(1)//使用构造函数初始化列表

template<class T>
NamedPtr<T>::NamedPtr(const string& initName,T* initPtr)::name(initName),ptr(initPtr)

{

}

(2)//使用构造函数体进行初始化

templae<class T>
NamedPtr<T>::NamedPtr()

{

name=initName;

ptr=initPtr;

}

分析:对于前面定义的NamedPtr类模板,上面两种方式的初始化运行时都不会有问题,但是存在运行效率问题。首先有一点你必须知道,在构造一个对象时,其内的成员变量会先被构造。使用第(1)种方式初始化时,stirng类型变量,name会去调用stirng类的拷贝构造函数,因为初始化列表提供了name(initName)并且初始化并不是此构造函数体的一部分,函数体里边是空的。此种方法,只调用了一次string的构造函数。当使用第(2)中方式初始化时,类成员stirng类型的默认构造函数会被执行一次,当进入模板类的构造函数时,又调用了string类的赋值函数,因此,存在对string类的两次调用。

综上:两种方式的初始化效率不同。

2.

我们再来改变一下,模板类NamedPtr的定义,只是简单的将两个类成员改成常类型的形式。

template<class T>
class NamedPtr
{
 public:
  NamedPtr(const string& initName,T* initPtr);
  friend ostream& operator<<(ostream &os,NamedPtr<T> co);
 private:
   const string name;
   T*  const ptr;//类类型指针成员
};

分析:成员变量改成常类型后,1里边的两种初始化方式就截然不同了,第(1)中仍然会正常执行,但第二种就会出现编译错误(或出现在连接时期),因为对于常类型,我们只能初始化,而不能赋值

综上:我们要尽量使用初始化列表形式而不要在构造函数里赋值。

3.

但是当某个类中有大量的基本类型变量需要赋值,此时

template<class T>

NamedPtr<T>::NamedPtr(const string& initName,T* initPtr)::name(initName),ptr(initPtr),m(1),n(2),p(2),q(4)..... //m,n等为类中整形成员变量

{

}这样的初始化列表此时就很容易出错。

变通方法:在类中定义一个私有函数如 :

Init()

{

m=1;n=2;p=3;q=4...;

}然后在初始化列表构造函数中调用Init函数就完成了,哈哈,是不是简单些...

 

你可能感兴趣的:(C++,初始化列表,构造函数体)