每个类都分别定义了它的对象初始化的过程,类通过一个或几个特殊的成员函数来控制其对象的初始化过程,这些函数称为构造函数
- 构造函数名字与类名相同
- 构造函数没有返回类型
- 不同于其他成员函数,构造函数不能被声明为const
- 构造函数可以重载和带默认值
类通过一个特殊的构造函数来控制默认初始化过程,这个函数叫做默认构造函数,一般情况下,是一个没有形参值的空函数。
如果我们没有显式地定义构造函数,编译亲就会为我们隐式地生成一个默认构造函数,又称为合成的默认构造函数
初始化规则:
- 如果存在类内的初始值,用它来初始化成员。
- 否则,默认初始化该成员。
需要我们注意的是:某些类不能依赖于合成的默认构造函数
- 一旦我们定义了自己的构造函数,那么除非我们再定义一个默认的构造函数,否则类将没有默认构造函数
- 如果类内含有内置类型或者复合类型的成员,如果类内没有提供初始值,那么将会被默认初始化,而产生未定义。
- 如果类中包含了一个其他类的成员且该成员的类无构造函数
- 构造函数可以进行重载
在C++11新标准下,可以用=default来要求编译器生成默认的构造函数。
定义构造函数时,既可以用初始化列表的方法,也可以用函数体进行成员赋值的方法。
有时我们可以忽略数据成员初始化和赋值的影响,但并非总能这样
如果成员是const,引用,或者某种未提供默认构造函数的类类型,我们必须通过构造函数初始值列表来进行。所以建议使用构造函数初始值,且最好令构造函数初始值的顺序与成员声明的顺序保持一致
委托构造函数
C++11标准扩展了构造函数初始值的功能,一个委托构造函数使用它所属的类的其他构造函数执行自己的初始化过程,或者说它把自己的一些(或者全部)职责委托给了其他构造函数。
可以简化了一些重复操作
class X {
int a;
// 实现一个初始化函数
validate(int x) {
if (0<x && x<=max) a=x; else throw bad_X(x);
}
public:
// 三个构造函数都调用validate(),完成初始化工作
X(int x) { validate(x); }
X() { validate(42); }
X(string s) {
int x = lexical_cast<int>(s); validate(x);
}
// …
};
//简化后-----------------------------------------
class X {
int a;
public:
X(int x) { if (0<x && x<=max) a=x; else throw bad_X(x); }
// 构造函数X()调用构造函数X(int x)
X() :X{42} { }
// 构造函数X(string s)调用构造函数X(int x)
X(string s) :X{lexical_cast<int>(s)} { }
// …
};
但是注意不能生成委托环
即必须有一个基本的构造函数,不能环环委托,否则编译出错
#include <iostream>
using namespace std;
class A
{
private:
int i=5;
string str="初始值";
public:
A(string ss):A(555){
str=ss;
}
A(int ii):A("OK"){
//不能写成AA(int ii):A(),i(ii)
//委托构造函数不能再利用初始化器初始化其他数据成员
i=ii;
}
void show(){
cout<<"i="<<i<<",str="<<str<<endl;
}
};
int main()
{
A a(10);
a.show();
}