构造函数的初始化顺序 与 初始化列表。

每个类中都有一个或多个构造函数 (constractors),用来初始化类中的成员。

构造函数 由系统自动调用。即 每当创建一个 相应类的对象时,系统会自动选择最佳匹配的构造函数 来初始化该对象的数据成员。

但是,构造函数的初始化顺序又是怎样的呢?


例如:

声明一个 Test 类。

class Test
{
public:
   Test ();
private:
   string a;
   string b;
   int c;
}

定义其构造函数:

Test::Test (string& i,string& j,int k)
{
   a = i;
   b = j;
   c = k;
}

c++ 规定:对象的成员变量的初始化动作 发生在 进入构造函数本体之前。

也就是说,在系统调用 Test 类的构造函数之前,首先对 数据成员 a、b、c 进行了初始化。


对于内置数据类型(基本数据类型) 而言,其初始化是不确定的。也就是说,c 可能被初始化 也可能不会。

对于标准类 或 用户自定义类 类型而言,会首先调用其 默认构造函数对其进行初始化。

即 对于 string 类型的变量 a 和 b 而言,系统首先调用 string 类的默认构造函数 对其进行初始化,紧接着在 Test 类的构造函数中,对 该变量进行赋值。即 "伪初始化"。

也就是说,系统首先调用了 string 类的默认构造函数 将 a 初始化为 空,然后立刻在 Test 类的构造函数中将其赋予了新值。这样一来,string 类的默认构造函数就变得没有意义。而且还降低了 Test 类构造函数的效率。

顺便说一下,系统对数据成员的初始化 (即 调用相应类型的默认构造函数) 的顺序 是由 其在类中声明的先后决定的。

如 在上例中,首先初始化 a,接着是 b。



为了提高 类的构造函数的 效率,通常 使用 构造函数的初始化列表 (member initialization list) 来直接初始化 数据成员。

也就是说,上例的构造函数 可以写成:

Test::Test (string& i,string& j,int k) : a(i), b(j), c(k) {} 

此时,系统直接调用其成员变量所对应的类型的 拷贝构造函数来初始化 相应成员变量。

比起 先调用成员变量的默认构造函数,然后再对其赋值,直接调用它的 拷贝构造函数 来初始化它 显然效率会比较高。

而且,此时才是真正意义上的初始化 成员变量。




啰里八唆的说了这么多,连我自己都觉得很婆妈。干脆来个总结吧。

  • 系统在调用 类的构造函数之前,首先会对类 的数据成员 进行默认初始化 (通过调用 数据成员的默认构造函数)。
  • 对于上面 第一种构造函数的形式而言,只是对 数据成员进行赋值,是"伪初始化"。
  • 上面第一种和第二种 构造函数的形式 对于内置类型而言,成本是相同的。
  • 对于 构造函数而言,上面第二种(初始化列表的形式) 比 第一种 (赋值形式) 的效率更高。一般建议使用 构造函数的初始化列表 形式。




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值