初始化函数列表

初始化函数列表
与其他 函数不同, 构造函数除了有名字, 参数列表函数体之外,还可以有初始化列表, 初始化列表以冒号开头,后跟一系列以逗号分隔的初始化字段。例:
class foo
{
public:
foo(string s, int i):name(s), id(i){} ; // 初始化列表
private:
string name ;int id ;
};

1  好多书籍都建议我们直接使用初始化列表为成员进行初始化,为什么呢?

我想原因有二:

①考虑到效率

②有些成员不得不这么做(const,引用)

为什么使用初始化列表就效率呢?

其实也不一定,

对于内置类型,在函数体内赋值和在初始化列表中初始化两者的效率是等同的。但是为了美观和一致性的问题,《Effective C++》作者建议我们还是用初始化列表进行。但是这也不是在所有情况下都是必须的。若一个类的构造函数很多的时候,这时每个构造函数都有自己的初始列,这样多份成员的初始列就会导致烦人的重复。这时我们可以选择那些“赋值表现得像初始化一样好”的成员变量,改用它们为赋值。然后把他们放到一个函数中,供所有的构造函数调用。

对于类类型,两者的效率就相差很多了:

初始化列表的执行发生在进入函数体之前,它是在调用构造函数是进行初始化的。而对于函数体内的赋值(非初始化,而是赋值),它是首相调用了类的默认构造函数来初始化成员变量,而后在函数体中调用赋值函数为成员变量赋值的。显然这个和初始化列表相比默认构造函数的调用就浪费了。效率低了很多。

有些成员变量必须用初始化列表

const 和引用 类型的成员变量必须得用初始化列表进行初始化。其实这没什么高明的,也并不是一个明文规定。而是为遵守我们另一个规则而必须这么做。这个规则就是”const和引用类型的变量必须初始化“。而我们通过上面也明白了,函数体内是赋值而非初始化,若我们将const和引用类型的成员变量放在构造函数的函数体内的话。那么const和引用类型的变量将会没有初值,即没被初始化,根据我们另一个规则,当然会发生错误,编译器不允许我们这么做的。故:我们在构造函数中必须选择初始化列表对const和引用类型的成员变量进行初始化。

2 初始化列表的初始化顺序

初始化列表的初始化顺序并不代表成员变量的初始化顺序,C++有着十分固定的”成员初始化顺序“,即:

①基类成员更早于派生类成员进行初始化

②类内部总是按成员变量的声明顺序依次进行初始化的。

由此我们是不是有一个想法啊?若我们定义了一个类:

Code:
  1. #include <iostream>   
  2. using namespace std;   
  3. class base   
  4. {   
  5. public:   
  6.   base():p(new int[size]),size(4) //注意这里   
  7.   {   
  8.     for (int i=0; i<4; ++i)   
  9.     {   
  10.         p[i] = i;   
  11.     }   
  12.     for (int i=0; i<4; ++i)   
  13.     {   
  14.         cout << p[i] << " ";   
  15.     }   
  16.   }   
  17. private:   
  18. int *p;   
  19. size_t size;   
  20. };   
  21. int main()   
  22. {   
  23.     base t;   
  24.    system("pause");   
  25.     return 0;   
  26. }  

我们用该类定义一个对象,然后运行。看下结果。结果什么也没有(VC2008)。。为什么呢?有些同学可能相到了。看下我们的初始化列表 

Code:
  1. base():p(new int[size]),size(4)  

我们是先为p申请的空间,此时size初始未初始化状态。当然运行不成功了。。好,那我们改过来:

Code:
  1. #include <iostream>   
  2. using namespace std;   
  3. class base   
  4. {   
  5. public:   
  6.   base():size(4),p(new int[size])//注意改过来了   
  7.   {   
  8.     for (int i=0; i<4; ++i)   
  9.     {   
  10.         p[i] = i;   
  11.     }   
  12.     for (int i=0; i<4; ++i)   
  13.     {   
  14.         cout << p[i] << " ";   
  15.     }   
  16.   }   
  17. private:   
  18. int *p;   
  19. size_t size;   
  20. };   
  21. int main()   
  22. {   
  23.     base t;   
  24.     system("pause");   
  25.     return 0;   
  26. }  

运行一下,还是没有,原因在那里呢?看下我们的声明顺序,

Code:
  1. private:   
  2. int *p;   
  3. size_t size;  

呵呵,明白了吧。好我们改过来:

Code:
  1. #include <iostream>   
  2. using namespace std;   
  3. class base   
  4. {   
  5. public:   
  6.   base():size(4),p(new int[size])   
  7.   {   
  8.     for (int i=0; i<4; ++i)   
  9.     {   
  10.         p[i] = i;   
  11.     }   
  12.     for (int i=0; i<4; ++i)   
  13.     {   
  14.         cout << p[i] << " ";   
  15.     }   
  16.   }   
  17. private:   
  18. size_t size;//改过来啦   
  19. int *p;   
  20. };   
  21. int main()   
  22. {   
  23.     base t;   
  24.    system("pause");   
  25.     return 0;   
  26. }  

运行一下,结果出现了。。呵呵。此时,无论你如何改初始化列表都不影响。由此就可以证明我们上面的结论②了吧。

既然到这里了,我们来证明下柳涛老师一篇日志的内存问题吧:看下面代码:

Code:
  1. #include <iostream>   
  2. using namespace std;   
  3. int a = 4;   
  4. int b = 5;   
  5. int c = 6;   
  6. int d = 7;   
  7. class base   
  8. {   
  9. public:   
  10.   base():p(&a)//注意这里   
  11.   {   
  12.     for (int i=0; i<4; ++i)   
  13.     {   
  14.         p[i] = i;   
  15.     }   
  16.     for (int i=0; i<4; ++i)   
  17.     {   
  18.         cout << p[i] << " ";   
  19.     }   
  20.     cout << endl;   
  21.     cout << "a: " << a << endl;   
  22.     cout << "b: " << b << endl;   
  23.     cout << "c: " << c << endl;   
  24.     cout << "d: " << d << endl;   
  25.   }   
  26. private:   
  27. int *p;   
  28. };   
  29. int main()   
  30. {   
  31.     base t;   
  32.     system("pause");   
  33.     return 0;   
  34. }  

我们看下输出结果:

Code:
  1. 0 1 2 3   
  2. a: 0   
  3. b: 1   
  4. c: 2   
  5. d: 3  

为啥b c d的值都被改变了呢?我们紧紧是让p指向了a啊。这就是柳涛老师的讲的内存问题的。原文地址是http://student.csdn.net/space.php?uid=91288&do=thread&id=2351

对于a,b,c,d;首相操作系统为变量分配空间(从低地址开始分配):首相是a,然后是b,c,d,由于他们都是整型,故为他们分配的空间是挨着的。当我们把p指向a后,若我们操作p[0]就相当于操作a了,同样p[1] 就是b了。.....

若我们改变一下:

Code:
  1. int a = 4;   
  2. char b = 5;//注意这里改了   
  3. int c = 6;   
  4. int d = 7;   

再次输出结果,结果不变.为什么呢?

Code:
  1. struct test1   
  2. {   
  3.     int a;   
  4.     char b;   
  5.     int c;   
  6.     int d;   
  7. };   
  8. struct test2   
  9. {   
  10.     int a;   
  11.     int b;   
  12.     int c;   
  13.     int d;   
  14. };  

我们可以输出一下这两个结构体的大小:

是一样的,都是16。在内存分配时,讲究字节对齐。故第一个char b;后面补充了三个字节。即:我们申请了还是相当于4个整型的空间。

若我们改成以下这样:

Code:
  1. struct test   
  2. {   
  3.     int a;   
  4.     char b;//注意这里   
  5.     char c;//注意这里   
  6.     int d;   
  7. };  

结果就变多了。。

Code:
  1. 0 1 2 3   
  2. a: 0   
  3. b: 1   
  4. c:   
  5. d: 2  

这就是结果.此时我们相当于申请了三个整型的空间,b,c占一个。故在我们移动指针p的时候第一个指向a,a = 0;第二个就到b,c那个整型空间,第三个就到d了,故d = 2;在b,c所占的整型空间里我们放进了整型值1.因为b处在该空间的开始位置,故通过b我们输出了1.c初始第二个字节开始的位置,从此开始将什么也输不出来。呵呵。关于内存空间分配的问题有太多东西了。。更多的东西都需要我们自己慢慢去摸索了。。加油大家,一起努力学习!


http://blog.csdn.net/wangfutao01/article/details/6470612


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值