构造函数
1、 什么是构造函数
每个类都分别定义了它的对象被初始化的方式,类通过一个或几个特殊的成员函数来控制其对象初始化的过程,这些函数即——构造函数。
构造函数的任务就是初始化对象的数据成员,无论何时只要类的对象被创建,就会执行构造函数。
2、 构造函数与其他函数的异同
相同之处:
①构造函数有一个(也可能是0个)参数列表和一个(也可能是0个)函数体。
②一个类可以包含多个构造函数,这和重载函数是一样的
相异之处:
①构造函数的名字和类名相同,而其他函数则不行。
②构造函数没有返回类型。
③构造函数不能被声明成const。
3、 默认构造函数
有时候我们没有为类中的对象提供初始值,但是其对象肯定是要初始化的,实际上它们执行了默认初始化的过程。类通过一个特殊的构造函数来控制默认初始化过程,这个函数叫做——默认构造函数。默认够造函数无须任何的实参。
如果我们的类没有显示的定义构造函数,那么编译器会为我们隐式的定义一个默认构造函数——合成的默认构造函数。
一般来说,对于任何的类都需要定义其自己的默认构造函数,因为有时候某些类不能依赖于合成默认构造函数,原因有三点:
①编译器只有在发现类不包含任何构造函数时才会替我们生成一个默认构造函数。一旦定义了一些其他的构造函数,那么除非我们再定义一个默认构造函数,否则将没有默认构造函数。
②对于某些类来说,合成的默认构造函数可能执行的是错误的操作。比如在类中数组或者指针类型被默认初始化,那他们的值是未定义的。
③有时候编译器不能为某些类合成默认的构造函数。比如,如果类中包含一个其他类的类型成员,且这个类型成员没有默认构造函数,那么编译器将无法初始化该成员。
4、 定义构造函数
以下面的例子开始作介绍:
struct Sales_data{
Sales_data() = default; //采用默认构造函数
Sales_data(const string &s, unsigned int n,double p):
bookNo(s),units_sold(n),revenue(p*n){ }
//构造函数初始值列表
};
在上面的程序段中,
Sales_data() = default;
此构造函数不接受任何的形参,因此他是一个默认构造函数。在这里定义这个构造函数的意义在于我们既需要其他形式的构造函数,也需要默认构造函数。这里的这个函数完全等同于使用合成的默认构造函数。
在C++11新标准中,如果我们需要默认行为,那么可以通过在参数列表后面写上=default来要求编译器生成构造函数。
再来看这句程序:
Sales_data(const string &s, unsigned int n,double p):
bookNo(s),units_sold(n),revenue(p*n) { }
这个定义中出现了新的表达方式和新的成分。我们将上面的语句分为三个部分:
1、“()”中的形参列表;
2、冒号“:”和花括号“{}”之间的代码。
3、“{}”中的内容。
对于1和3我们都好理解,对于2中新出现的表达方式,我们称之为——构造函数初始值列表。这个初始值列表的功能是负责为新创建的对象的一个或几个数据成员赋初始值。构造函数初始值是成员名字的一个列表,每个名字后面紧跟着用“()”括起来的成员初始值。不同的成员初始化通过逗号分隔开。
另外,我们注意到上面的两个构造函数的函数体都是空的。这是因为这些构造函数的唯一目的就是为数据成员赋初值。
下面再看一段代码:
Sales_data:Sales_data(std::istream &is)
{
read(is , *this); //read函数的作用是从is中读取数据并存储在
//this对象中
}
上面这个构造函数是在类的外部定义的。在外部定义与在类的内部定义,方法是一样的。只是这个构造函数没有构造函数初始值列表,或者说其初始值列表是空的。