1、构造函数
构造函数的任务是初始化类对象的数据成员,无论何时只要类的对象被创建,就会执行构造函数。
- 构造函数名与类名相同
- 没有返回类型
- 可以重载
- 不能声明成const
1.1、合成的默认构造函数
如果我们没有为类显式的定义构造函数,编译器会为我们隐式的定义一个默认构造函数(不需要任何参数)又叫做合成的默认构造函数)这个构造函数按照下面规则初始化类的数据成员:
- 如果有类内初始值,用它来初始化成员(比如上面的units_sold=0,revenue=0.0)。类内初始值必须以=或{}表示。
- 否则,默认初始化(如bookNo被初始化为空字符串)。
1.2、自定义默认构造函数
一般情况下,类都需要定义一个默认构造函数,主要有以下三个原因:
- 一旦定义了其他构造函数,除非我们自己再定义一个默认构造函数,否则这个类将没有默认构造函数。
- 若类中含有内置类型或复合类型(比如数组和指针)的数据,如果没有提供类内初始值(有的编译器可能不支持类内初始值),使用合成的默认构造函数的值将是未定义的。
- 如果类中包含其他类的对象,而这个对象没有默认构造函数,那么编译器不能为类合成默认构造函数,我们必须自己定义一个默认构造函数。
(1)default
Sales_data()=default;
函数名与类名相同,没有参数列表,参数列表后面加上=default要求编译器生成默认构造函数。
(2)默认实参构造函数
如果一个构造函数为所有参数都提供了默认实参,则它实际上也定义了默认构造函数。
class C1{
public:
C1(int );
void prt(){ cout << i; };
private:
int i;
};
C1::C1(int ii=9){
i = ii;
}
C1 cc;//定义一个对象
cc.prt();//输出9
1.3、使用默认构造函数
注意下面2种定义:
C1 obj1();//obj1是返回值为C1类型的函数
C1 obj2;//obj2使用默认构造函数初始化
1.3、构造函数初始值列表
Sales_data(const string & s,unsigned n,double p):bookNo(s),units_sold(n),revenue(p*n){}
冒号和花括号中间的部分就是构造函数的初始值列表。如果某个数据成员没有被初始值列表包括,这个值将以与合成默认构造函数相同的方式隐式初始化,对于没有初始值列表的构造函数,也是以同样的方式初始化。
2、构造函数初始值列表
(1)与一般的构造函数的区别
Class1::Class1(const string &s,int n){
bookNo=s;
units_sold=n;
};
这种构造函数时对数据成员执行的是赋值操作,该类的成员在构造函数体之前已经执行了默认初始化。而使用初始值列表的构造函数则直接初始化了类的数据成员。
(2)必须使用构造函数初始值列表的类型
如果成员是const、引用、或属于某种未提供默认构造函数的类类型,我们必须通过构造函数初始值列表为这些成员提供初值:
class C1{
public:
C1(int ii);
private:
int i;
const int ci;
int &ri;
};
C1::C1(int i){
i=ii;//正确
ci=ii;//错误,不能给const赋值
ri=ii;//错误,ri未初始化
}
(3)成员初始化的顺序
构造函数初始值列表只用于初始化成员的值,成员的初始化顺序是按照它们在类中出现的顺序执行的,而与它们在构造函数初始值列表中的顺序无关:
class C1{
int i;
int j;
public:
C1(int val):j(val),i(j){}//构造函数首先用j初始化i,而j是未定义的,程序报错。
};