构造函数
一、定义
构造函数存在的意义是初始化对象,不是开空间创建对象,在对象实例化的时候编译器自动调用构造函数。
二、特征
① 与类名相同
② 可以重载
③没有返回值
④ 对象实例化的时候编译器自动调用构造函数
三、默认构造函数
⑴ 无参构造函数、全缺省构造函数、编译器自动生成的构造函数(无参构造函数) 均为默认构造函数。
⑵ 默认构造函数在类中只能存在一个,且编译器自动生成的构造函数是当类中没有实现无参构造或者全缺省构造函数且没有实现带参的构造函数,才会自动生成,实例化对象时,若是类中没有默认构造函数,必须显示调用,否则编译报错。
⑶ 显示调用构造函数时,会选择最匹配的构造函数实例化对象,不会选择默认构造进行实例化对象。
⑷ C++98中,编译器自动生成的默认构造函数,内置类型为随机值,C++11打上补丁后,可在声明处可以给默认值作为初始化。
四、初始化
⑴ 构造函数初始化对象时,内置类型构造函数自身处理,自定义类型是调用本身的构造函数。
五、初始化列表
⑴ 定义:在构造函数体内赋值作为初始化不同的是,初始化列表只能够初始化一次,每个成员变量在初始化列表中只能出现一次,尽量使用初始化列表进行初始化。
⑵ 使用:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括号中的初始值或表达式。
class A
{
public:
A(int a, int b)
:_a(a), _b(b)
{}
private:
int _a;
int _b;
};
⑶ 必须在初始化列表中初始化的成员变量:引用变量、const变量、自定义类型(需要显示调用构造函数或者没有默认构造函数)
⑷ 初始化列表初始化成员变量与成员变量声明先后顺序有关,而不是按照初始化列表中的顺序来。
析构函数
一、定义
对象在销毁时会自动调用析构函数,完成对象中资源的清理工作,而不是完成对对象本身的销毁。
二、特征
① 析构函数名是在类名前加上字符 ~
② 无参数无返回值类型,无法重载。
③一个类只能有一个析构函数。若未显式定义,编译器自动生成默认的析构函数
④ 对象生命周期结束时,编译器自动调用析构函数
三、析构函数写法
⑴ 对于内置类型( 除指针外 )的成员变量,可以不用写(栈帧结束后系统会自动回收),指针若是在构造时申请了资源,则需要在析构函数中释放掉。
⑵ 对于自定义类型,编译器会自动调用该类型的析构函数进行释放资源。
class A
{
public:
~A() {}
private:
int _a;
int _b;
}
拷贝函数
一、定义
只有单个形参,该形参是对本类型对象的引用(常用const修饰),在用已存在的该类型对象创建新对象时由编译器自动调用。
二、特征
① 拷贝构造函数是构造函数的一个重载,与构造函数一样可以使用初始化列表, 初始化列表中使用自身成员变量来初始化对方成员变量时,不受限定符的影响。
② 拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错,因为会引发无穷递归调用(自己调用自己)。在传引用的时候,若是没有特殊需求,通常用const来修饰参数,避免出现无意修改参数导致程序出现问题的情况。
③ 若是未显式定义,编译器会生成默认拷贝构造函数。 默认的拷贝构造函数会将成员变量按字节完成拷贝,这种拷贝叫做浅拷贝。如果是需要深拷贝,则需要自己显示定义拷贝构造函数,否则会出现共用一块空间(出现空间争抢、析构函数会释放两次资源导致编译器报错)。自定义类型则是调用其自身的拷贝构造函数。
class A
{
public:
A(const A& self)
:_a(self._a)
,_b(self._b)
{}
private:
int _a;
int _b;
}
赋值重载
一、定义
C++为了增强代码的可读性引入了运算符重载,赋值重载就是=运算符的重载。
二、特征
① 格式
class A
{
public:
A& operator=(const A& a)
{
if(this != &a)
{
_a = a._a;
_b = a._b;
}
return *this;
}
private:
int _a;
int _b;
}
② 提供返回值是支持连续赋值
③ 判断是否自己给自己赋值
④ 赋值重载是类的专属,不能实现全局函数,防止编译器自动生成的与全局的形成冲突。
⑤ 未显示定义,编译器自动生成默认赋值重载函数。是以值拷贝方式来拷贝,需要深拷贝时,需要自己显示定义,否则会出现共用一块空间(出现空间争抢、析构函数会释放两次资源导致编译器报错)。
三、注意点
使用的时候与拷贝构造函数会发生混淆,如图
class A
{
//构造
A()
{}
//拷贝构造
A(const A& a)
{}
//赋值重载
A& operator=(const A& a)
{
if(this != &a)
{
//....
}
return *this;
}
};
int main()
{
A a1;
A a2 = a1; //这是调用拷贝构造函数,a2是实例化中的对象,需要初始化
A a3;
a3 = a1; //这是调用赋值重载函数,因为a3是已存在的对象
return 0;
}