目录
1.构造函数
2.析构函数
3.拷贝构造函数
4.赋值操作符重载
5.两个取地址操作符的重载
在C++中当你创建一个空类,那这个空类是什么都没有吗?不是的,编译器会默认帮你生成六个成员函数
1.构造函数
构造函数是特殊的成员函数,虽然名称是构造,但不是参与对象的创建,而是完成对对象内成员变量的初始化,构造函数有以下特点:
- 构造函数和类名相同
- 没有返回值
- 构造函数可以重载
- 对象实例化时自动调用构造函数
构造函数完成在类对象创建时由编译器自动调用,保证每个成员都有一个合适的初始值,保证在对象生命周期内只完成一次初始化
class A
{
public:
//无参的构造函数
A()
{
}
private:
int _a;
};
构造函数可以重载,根据参数的不同实现不同的构造函数
默认构造函数只有三种:
- 1.我们不写编译器默认生成的构造函数
- 2.无参的构造函数
- 3.全缺省的构造函数
类对象中默认构造函数只能有一个,有多个会报错,编译器无法识别要调用哪一个构造函数
class A
{
public:
A()
{}
A(int a = 1)
{
_a = a;
}
private:
int _a;
};
int main()
{
A a1;
return 0;
}
当创建一个类对象,不传参就会调用默认构造函数,可是有两个默认构造函数,这样编译器就无法识别要调用哪一个
默认构造函数对内置类型不做处理,对自定义类型会去调用自定义类型的默认构造函数
class B { public: B(int b = 1) { _b = b; } private: int _b; }; class A { public: private: int _a; B _b; }; int main() { A a1; return 0; }
而当B中没有默认构造函数时,A中又没有显示调用B的构造函数时,创建A对象就会报错
2.析构函数
析构函数也是特殊的成员函数,完成的是对象销毁时类内成员变量的清理工作
- 析构函数跟类名相同,函数名前加上~
- 没有返回值和参数
- 对象内有且只有一个析构函数
- 在对象生命周期结束时自动调用析构函数
class A { public: ~A(){}//析构函数 private: int _a; B _b; };
当你没有显示定义析构函数时,编译器会给你默认生成一个析构函数。
对内置类型不做处理,对自定义类型去调用它的析构函数
析构函数不管你是显示写的还是编译器默认生成的,它都会去调用自定义类型的析构函数
当对象内有成员变量有在堆上申请空间时,则需要我们显示写析构函数去进行释放。
而对于自定义类型则会调用它的析构函数
如果成员变量在堆上申请了空间而没有调用析构函数清理则就会内存泄漏
函数运行时创建对象,实际是在函数的栈帧中存放,而结合栈后入先出的特性,后构造的会先析构。
3.拷贝构造函数
拷贝构造函数,第一个参数是类类型对象的引用(一般用const修饰),在用一个已存在的对象创建新对象时 编译器会自动调用
- 拷贝构造函数是构造函数的一种重载
- 第一个参数是类类型的引用
编译器默认生成的拷贝构造对内置类型做值拷贝,对自定义类型会去调用自定义类型的拷贝构造
但这里的值拷贝只是把原对象变量的值按照字节一个个拷贝给新对象,当有指针变量时,就会出现两个对象中的指针成员变量存放的是一样的地址,这样在使用和销毁时就会出现问题。
销毁时调用析构函数,两个对象那就是两次析构,也就是说会对指针变量进行两次析构,从而程序崩溃
这里就需要显示的定义拷贝构造从而进行深拷贝
需要重新申请空间,然后再进行值拷贝
需要注意的是,拷贝构造的第一个参数只能是类类型对象的引用,因为当是类类型对象时,就会发生无穷递归。
A(A a){}//不带引用的拷贝构造
在C++中规定,当自定义类型传参时使用形参传参时,会去调用本类型对象的拷贝构造构造一个临时对象给形参。而你传参时调用的本类型对象的拷贝构造又需要传参,你又传的是形参,这时就会一直传参发生拷贝构造,而拷贝构造又是类类型对象接收,就又会发生拷贝构造
4.赋值操作符重载
赋值运算符重载需要用到关键字operator,运算符重载函数有返回值和参数,运算符是几元的就有几个参数,C++规定运算符重载不可以改变运算符本来的逻辑,不可创建不存在的运算符进行重载
Date& operator=(const Date& d)
{
//赋值
}
以下五个运算符不可重载:
.* sizeof . ?: ::
而赋值运算符=的重载我们不显示实现,编译器也会默认给我们生成一个,默认生成的赋值重载对内置类型完成值拷贝,对自定义类型会去调用它的赋值运算符重载。
这里就会遇到和拷贝构造相同的问题,编译器默认生成的赋值运算符重载仅仅只是浅拷贝,而浅拷贝在析构时程序会崩溃,所以这里也一样要进行深拷贝
5.两个取地址操作符的重载
取地址操作符的重载编译器默认生成的就已经够用了,所以这里不过多介绍