Effective C++学习笔记之“尽量使用初始化而不要在构造函数里赋值”

在对类成员变量初始化的时候,我们很多时候没有注意到,在类构造函数的初始化列表中初始化成员变量,和在构造函数中赋值初始化成员变量的差别是很大的,不仅表现在程序的执行效率上,同时还有语法上的区别。类定义如下:

   1:  class String 
   2:  { 
   3:  public: 
   4:      String() 
   5:      { 
   6:          cout "String::String()" 

  
   7:      } 
   8:      String(String& str) 
   9:      { 
  10:          m_value = str.m_value; 
  11:          cout "String::String(String& str)" 

  
  12:      } 
  13:      ~String(){} 
  14:      String& operator=(String& src) 
  15:      { 
  16:          m_value = src.m_value; 
  17:          cout "String::operator =" 

  
  18:          return *this; 
  19:      } 
  20:  protected: 
  21:      int m_value; 
  22:  }; 
  23:  
  24:  class Base 
  25:  { 
  26:  public: 
  27:      Base(String& str); 
  28:      Base(String& str, int flag); 
  29:      ~Base(){} 
  30:  protected: 
  31:      String      m_string; 
  32:      const int m_flag; 
  33:  }; 
  34:  
  35:  Base::Base(String& str) 
  36:  { 
  37:      m_string = str; 
  38:  } 
  39:  
  40:  Base::Base(String& str, int flag):m_string(str), m_flag(flag) 
  41:  { 
  42:  }
<style type="text/css"> .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }</style>

Base类包含了两种类型的构造函数,分别是在构造函数中初始化成员变量以及在初始化列表中初始化成员变量。下面的代码是体现出两种方式的差别:

1、在构造函数中初始化话成员变量

   1:  int main(int argc, int *argv[])
   2:  {
   3:      String str;
   4:  
   5:      Base base1(str);
   6:  
   7:      getchar();
   8:      return 0;
   9:  }

程序执行结果如下:

第一条输出是String str时调用构造函数产生的,这样base1对象的初始化会调用String的默认构造函数和String的=操作符函数

2、在初始化列表中初始化成员变量

   1:  int main(int argc, int *argv[])
   2:  {
   3:      String str;
   4:  
   5:      Base base2(str, 1);
   6:  
   7:      getchar();
   8:      return 0;
   9:  }
<style type="text/css"> .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }</style> <style type="text/css"> .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }</style>

程序执行结果如下:

从结果可以看出,两种不同的方式,执行的过程差别很大,前一种方式比后一种要多执行一个String的=操作符函数,所以在初始化列表中初始化成员变量的方式更加合理。

从C++语法上比较,成员变量m_flag是const int类型,它的初始化过程只能在构造函数的初始化列表中赋值,不能在构造函数中赋值。严格来说,对象的数据成员初始化过程已经在调用构造函数之前完成了,在构造函数中“初始化”,只是保证成员变量在别处引用之前给它一个确定的初值。

在程序的世界里,任何规则都不是绝对的合理,对于类中大量的固定类型的数据成员的初始化,比如这样

   1:  private:
   2:    int a, b, c, d, e, f, g, h;
   3:    double i, j, k, l, m;
<style type="text/css"> .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }</style>

这个时候在构造函数中赋值,比在初始化列表中初始化跟合理,把这个代码放在构造函数体里面赋值,看上去代码会更加赏心悦目,同时也不会导致额外的效率问题。只是很简单的问题,写下来是为了让自己理解更加透彻,能正确遵守这个规则,有不对之处,欢迎指出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值