钱能版c++关于成员初始化相关章节,以一个学生学号类的代码引出,如下:
- #include <iostream>
- using namespace std;
- //学号类
- class StudentID{
- int value;
- public:
- StudentID(int id=0){
- value=id;
- cout<<"学生id赋值为:"<<value<<endl;
- }
- };
- //学生类
- class Student{
- string name;//学生姓名
- StudentID id;//学生学号
- public:
- Student(string n="匿名",int ssID=0){
- cout<<"创建学生"+n+"\n";
- name=n;
- StudentID id(ssID);//本意想要重新对id赋值,然而其实是创建一个局部对象而已。
- }
- };
- int main()
- {
- Student s("张三",59);
- return 0;
- }
我们已经知道,如上所示,为id重新指派,达不到目的的。
根据个人愚见,可以这样换种思维考虑这个问题,
这里id作为学生类里面的一个成员属性,他是StudentID类的对象,它的初始化借助于该类的构造函数,
作为子级别,它的构造函数理应发生在Student的构造函数之前(设想组装一个玩具人偶,我们是不是需要把身体的部件提前准备好呢。)
StudentID-->Student
于是引出了成员初始化列表这个东东,形式:
Student(Type a,Type b....):id(b){}
有点像StudentID id(b);==============>置于Student()之前。
本例没有提供:id(b)其实就等同于:id()
会调用对应的无参形式的构造函数。
可能有人说,既然是在Student初始化之前(或者严格说是在使用StudentID之前,准备好不就行了吗,比如放在Student构造函数开始处啦),通过构造函数,不行了,如上面那种,等于又构造了一个局部对象,可以用个Set之类的重新赋值,如下:
Student(string n="匿名",int ssID=0):id(){
//按照”子部件“在Student内部代码执行前准备好的原则,这里{之后开始处,studentid已经初始化完毕了。
id.set(59);//这样是可行的。
cout<<"创建学生"+n+"\n";
name=n;
}
修改代码如下:
StudentID:
void set(int v){
value=v;
cout<<"set函数中\n";
}
void print(){
cout<<value<<endl;
}
Student:
Student(string n="匿名",int ssID=0){
id.set(ssID);//重新赋值
cout<<"创建学生"+n+"\n";
name=n;
id.print();//打印出来看看
}
但这种分离式脱离构造函数本身了,区别就是
int a=123;
与int a; a=123;的区别了。
而且有时候,这种方式还不行,比如常量和引用,只能初始化一次。
这就说明了”成员初始化列表“引出的目的。
- //学号类
- class StudentID{
- int value;
- const int c;//常量
- int &rv;//引用
- public:
- StudentID(int id=0):c(123),rv(value){
- value=id;
- cout<<"学生id赋值为:"<<value<<endl;
- }
- ... ....