构造函数:
每个类都定义了它的对象被初始化的方式,类通过一个或几个特殊的成员函数来控制其对象的初始化过程,这些函数叫做构造函数。构造函数的任务是初始化类对象的数据成员,无论何时只要类的对象被创建,就会执行构造函数。
构造函数的名字和类名相同。和其他函数不一样的是,构造函数没有返回类型。除此之外类似于其他的函数,构造函数也有一个(可能为空的)参数列表和一个(可能为空的)函数体。类可以包含多个构造函数,和其他重载函数差不多,不同的构造函数之间必须在参数数量或者参数类型上有所区别。
不同与其他成员函数,构造函数不能被声明成 const 的,当我们创建类的一个 const 对象时,直到构造函数完成初始化过程,对象才能真正取得其 "常量" 属性。因此,构造函数在 const 对象的构造过程中可以向其写值。
合成的默认构造函数:
如果我们没有显示地定义构造函数,那么编译器就会隐式地定义一个默认构造函数(合成的默认构造函数)。一般情况下合成的构造函数按照如下规则初始化类的数据成员:
1.如果存在类内的初始值,用它来初始化成员
2.否则,默认初始化
合成的默认构造函数只适合非常简单的类,比如上一篇博客中的 Sales_data 类。对于一般类来说是必须要定义默认构造函数的:
1.编译器只有在发现类不包含任何构造函数的情况下才会生成一个默认的构造函数。一旦我们定义了一些其他的构造函数,那么除非我们再定义一个默认的构造函数,否则类将没有默认构造函数。
2.对于某些类来说,合成默认构造函数可能执行错误的操作。如果定义在块中的内置类型或复合类型(比如数组和指针)的对象被默认初始化,则它们的值将是未定义的。这条准则同样适用于默认初始化的内置类型成员。因此,含有内置类型或复合类型成员的类应该在类的内部初始化这些成员,或者定义一个自己的默认构造函数。否则,用户在创建类的对象时就可能得到未定义的值。
3.有的时候编译器不能为某些类合成默认的构造函数。如:如果类中包含一个其他类类型的成员且这个成员的类型没有默认构造函数,那么编译器将无法初始化该成员。
现在我们来给上篇博客中的 Sales_data 类添加几个构造函数:
1 struct Sales_data{ 2 //数据成员 3 std::string book_no; 4 unsigned units_sold = 0; 5 double revenue = 0.0; 6 7 //新增的构造函数 8 Sales_data() = default;//不接受任何实参,默认构造函数 9 Sales_data(const std::string &s): book_no(s){}//除了book_no外其他成员将使用类内初始值 10 Sales_data(const std::string &s, unsigned n, double p): book_no(s), units_sold(n), revenue(p * n){} 11 Sales_data(std::istream); 12 13 //之前的函数成员 14 std::string isbn() const { 15 return book_no; 16 // return this->book_no;//等价语句 17 } 18 Sales_data& combine(const Sales_data&); 19 double avg_price() const; 20 };
首先我们定义了其他构造函数,如前面所述,编译器不会再合成默认构造函数,所以我们通过 Sales_data() = default;显示地定义了一个默认构造函数。在 c++11 标准中,如果我们需要默认的行为,那么可以通过在参数列表后面写上 = default;来要求编译器生默认成构造函数。其中,= default 既可以和声明一起出现在类的内部,也可以作为定义出现在类的外部。和其他函数一样,如果 = default 在类内部,则默认构造函数是内联的,反之则不是内联的。(关于default:http://blog.csdn.net/a1875566250/article/details/40406883)
构造函数初始值列表:
1 Sales_data(const std::string &s): book_no(s){}//除了book_no外其他成员将使用类内初始值 2 Sales_data(const std::string &s, unsigned n, double p): book_no(s), units_sold(n), revenue(p * n){}
其中,和一般函数一样,花括号里面是函数体,不过这些构造函数唯一的目的就是为数据成员赋初值。不需要执行其他任务,所以函数体为空。冒号和花括号之间的是构造函数初始值列表,每个数据成员后面括号里的就是该数据成员的初始值,不同成员的初始化通过逗号分隔开来。
在类外部定义构造函数:
1 Sales_data::Sales_data(std::istream &is){ 2 read(is, *this);//read 函数的作用是从 is 中读取一条信息然后存入 this 中 3 }
和其他定义在外部的成员函数一样,我们需要用 :: 来指明该构造函数是哪个类的成员。
还需要注意的是该构造函数调用了 read 函数,所以该构造函数的定义必须写在 read 函数的声明之后。