浅浅介绍最近所学,希望有兴趣的读者老爷垂阅!
目录
1.再谈构造函数
本鼠在【C++】类和对象2.0中介绍说构造函数简单来说就是初始化用的,当然这个结论是对的。但是俺在【C++】类和对象2.0中一直是对构造函数的函数体进行操作,难道在构造函数的函数体内的语句是对对象的成员变量进行初始化操作吗?
本鼠都这么问了,那当然不是了,为什么构造函数的函数体内的语句不是对对象的成员变量进行初始化操作呢?
1.1.构造函数体赋值
在创建对象时,编译器通过调用构造函数,给对象中各个成员变量一个合适的初始值。
class Date
{
int _year;
int _month;
int _day;
public:
Date(int year=2003,int month=12,int day=12)
{
_year = year;
_month = month;
_day = _day;
}
};
int main()
{
Date d(2024, 7, 1);
return 0;
}
如上面的代码,给了对象d中各个成员变量一个合适的初始值,但是不能将其称为对对象中成员变量的初始化,构造函数体中的语句只能将其称为赋值,而不能称作初始化。因为初始化只能初始 化一次,而构造函数体内可以多次赋值。
构造函数体内多次赋值:
class Date
{
int _year;
int _month;
int _day;
public:
Date(int year=2003,int month=12,int day=12)
{
_year = year;
_month = month;
_day = _day;
_day = 10;//多次赋值
}
};
int main()
{
Date d(2024, 7, 1);
return 0;
}
如果构造函数体内的语句是对对象的成员变量进行初始化操作的话,我们不应该允许多次赋值!
所以构造函数的函数体内的语句是赋值而不是初始化!换句话说,构造函数的函数体不是对象的成员变量初始化的地方!
还有一个问题有待解决:
我们知道,类定义时,类的成员变量只是声明,如:
class Date
{
int _year;//成员变量声明
int _month;//成员变量声明
int _day;//成员变量声明
public:
Date(int year=2003,int month=12,int day=12)//成员函数的声明和定义
{
_year = year;
_month = month;
_day = _day;
_day = 10;//多次赋值
}
};
当对象实例化时,类类型对象的成员变量就整体定义了,开空间了,如:
int main()
{
Date d(2024, 7, 1);//对象实例化
return 0;
}
对象整体定义的位置我们知道,但是对象的具体成员变量定义的位置如何界定?
难道是对象的具体成员变量定义的位置是在构造函数的函数体当中吗,当然不是,原因跟上面一样,函数体内关于某成员变量的语句可以多次出现,如果说关于某成员变量的语句第一次出现是其定义,那么当关于其成员变量的语句多次出现时,难道其成员变量可以多次定义吗?
显然对象具体的成员变量不能多次定义,那么构造函数的函数体就不是对象的成员变量定义的地方!
对象的成员变量只能定义和初始化一次,所以构造函数开辟了初始化列表来界定成员变量的定义和初始化。
注意:语法上来说初始化列表是成员变量定义的地方,但是底层来说成员变量定义(开空间)不是初始化列表完成的。
1.2.初始化列表
初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟 一个放在括号中的初始值或表达式。如:
class Date
{
int _year;
int _month;
int _day;
public:
Date(int year=2003,int month=12,int day=12)
//初始化列表
:_year(1)
, _month(1)
,_day(1)
//函数体
{
}
};
int main()
{
Date d(2024, 7, 1);
return 0;
}
如上代码,初始化列表中:第一条语句就是成员变量_year定义的地方,2024是其初始值(给其初始化的值);第二条语句就是成员变量_month定义的地方,7就是其初始值;第三条语句……
语法上来说就是这样子的,运行成功!
注意:
- 注意1:每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次,定义亦然)
若是某成员变量在初始化列表多次出现,一定会报错!
class Date
{
int _year;
int _month;
int _day;
public:
Date(int year=2003,int month=12,int day=12)
//初始化列表
:_year(1)
, _month(1)
, _day(1)
,_day(2)//error C2437: “_day”: 已初始化
//函数体
{
}
};
- 注意2:尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型对象的成员变量, 一定会先使用初始化列表初始化。
就是说类类型对象的所有成员变量一定会先在初始化列表定义和初始化,不管你在初始化列表中是否显式写某成员变量,如果某成员变量没有显式写,编译器也会隐藏的将该成员变量“过一遍”初始化列表。当所有成员变量“过完”初始化列表,如果函数体有赋值语句,就会进入函数体进行赋值,从而赋值修改成员变量;如果函数体为空,那就不会赋值修改。
class Date
{
int _year;
int _month;
int _day;
public:
Date(int year=2003,int month=12,int day=12)
//初始化列表
:_year(1)
, _month(1)
//函数体
{
}
};
int main()
{
Date d(2024, 7, 1);
return 0;
}
当成员变量_day没有在初始化列表中显式写的时候,_day也一定先在初始化列表“走”了一遍,并用随机值初始化_day,所以能看到_day初始值是随机值。函数体内为空,没有对成员变量赋值修改,所以所有成员变量仍然是初始值。如图:
如果函数体内不为空,有赋值语句,我们看看:
class Date
{
int _year;
int _month;
int _day;
public:
Date(int year=2003,int month=12,int day=12)
//初始化列表
:_year(1)
, _month(1)
//函数体
{
_month = month;
_day = day;
}
};
int main()
{
Date d(2024, 7, 1);
return 0;
}
函数体内只对_month和_day进行了赋值修改,所以_month从1变成7,_day从随机值变成1:
- 注意3:类中包含以下成员,必须放在初始化列表位置进行初始化,就是必须在初始化列表位置显式写:
- const成员变量
- 引用成员变量
- 自定义类型成员且该类没有默认构造函数时
为什么呢?
1.const成员变量必须也只能在定义的时候初始化,一旦在定义的地方给定初始值就不能再修改了,所以必须在初始化列表显式写: