构造函数&析构函数&拷贝构造函数&赋值运算符重载特点:
1.构造函数 (有this指针)
系统会给默认构造
构造函数可以被重载(生而不同)
不能手动调到,因为其是对象生成的一部分
2.析构函数
析构函数不能被重载 (死亡方式一样)
可以手动调用 ==》 手动调用后析构函数退化成普通的成员方法
3.拷贝构造函数
拿一个已存在的对象来生成相同类型的新对象
默认的拷贝函数为 浅拷贝
(如果类成员变量有指针 需要考虑自己实现深拷贝)
形参一定要加引用 ==> 如果不加引用会造成:递归生成形参对象 但形参对象无法生成
4.赋值运算符的重载函数
拿一个已存在的对象来赋值给另一个相同类型的已存在对象
默认的赋值运算符的重载函数为 浅拷贝
实现赋值运算符的重载函数四步
1.自赋值判断
2.释放旧资源
3.开辟新资源
4.赋值
形参为const的原因:
1.防止修改实参
2.接收隐式生成的临时量
对象的创建:
1.内存的开辟 2.系统调用构造函数来初始化对象
对象的销毁:
1.堆内存等其他资源的释放 2.释放内存
如果销毁的两步反过来做就会导致内存泄漏,因为释放对象后无法在找到其中指针所指向的内存,也就没法将其释放
构造函数和析构函数的异同:
相同点:一般都是由系统调用的,其中都有this指针来指向要操作的对象的内存空间
不同点: 1.构造函数可重载,因为构造函数要实现"生而不同的"特点
析构函数不可重载,析构函数是释放资源的,同类不同的对象释放资源的方式都是一样的
2.构造函数不可手动调用,因为其是对象生成的一部分,假如没有生成对象,我们又怎么依靠对象去调用构造函数
析构函数可手动调用,但是在手动调用析构函数的时候,析构函数会退化为普通的成员方法,因此系统还会再调用析构函 数
拷贝构造函数:
拷贝构造函数是用已经存在的对象生成一个新的对象的方法
默认的构造函数是浅拷贝,如果我们的类成员变量中指针存在,我们就要考虑实现一个深拷贝的构造函数,因为浅拷贝会有一个问题,当我们操作浅拷贝出来的对象的时候,假如将其指针所指向的空间释放掉,则原对象再去析构的话,程序就会出现错误,因为一块空间不能被重复释放,当然这也只是浅拷贝会产生的一个问题
我们可以实现一个拷贝构造函数的原型:
String (const String& rhs)
{
this->ptr = new char[(strlen(rhs.ptr) + 1];
strcpy(this->ptr,rhs.ptr);
}
如上图所示,拷贝构造函数的参数列表里为: const String& rhs;
如果我们将其改为: const string rhs 会不会出错呢?答案是会出错,原因如下图:
因为实参传形参是一个初始化的过程,有push开辟形参的过程,为了防止上图出现的问题,一定在拷贝构造函数的参数列表里传递的是自定义类型的对象的引用,否则无法创建成功新的对象
赋值运算符的重载:
1.赋值运算符是拿一个已存在的对象来赋值另一个相同类型的已存在的对象
2.和拷贝构造函数一样,有指针存在要考虑实现深拷贝,因为默认的 赋值运算符重载方法 支持的是浅拷贝
赋值运算符是一个双目运算符,但是我们在实现其重载的时候,设计的函数模型如下:
Good& operator=(const Goods& rhs)
{
if(this != rhs) //1.是否为自赋值,不是则继续,是的话就退出
{
//2.delete 即释放对象所占的资源
//3.new 即给对象重新分配资源
//4.给this指针指向的变量赋值
}
}
/*
注释: 2和3两步是为了防止以下错误:
假设 a对象中有一个指针,其指向的空间为"hello"
b对象中有一个指针,其指向的空间为"hi"
当执行 b=a 时,其就会因为内存大小不满足而导致错误
*/
3.运算符重载方法的参数列表中可以不要那个引用(&)符号,就变成了:
operator=(const Goods rhs);
当使用的时候例如: Goods good2 = good2; //good2(good1)
先传形参,形参对象生成是凭借 拷贝构造函数 生成的,即: Goods rhs = good1 ;而拷贝构造函数是没有问题的,因此,不要这个引用(&)符号是可以的,但是建议加上,因为不加的话,中间形参对象是会被创建的,这个会使得效率变得低一些
4. int a = 10.1; 这个代码是没有问题的,系统会将10.1强转为int类型的数据,但是对于一个自定义的类,系统是不会将内置类型转换为自定义类型的,
但是,对于: goods1 = 10; 这句代码是可以成功的,goods1是一个类,系统会找到类中为Goods(int )的构造函数来生成一个临时的中间对象,依靠中间对象来进行赋值操作, 属于隐式生成临时对象
5. Goods good1;
goods1 = Goods(10);
这是显式的生成临时变量来进行赋值操作
关于上述提到的临时中间量:
1.内置类型,如int, 它生成的临时量为常量, 如:int i=0; i++; i++就会生成一个临时量
2.自定义类型,生成的临时量为 变量
3.隐式生成的临时量为 常量, 普通引用不能引用常量
4.关于临时量的优化:
临时量的生成如果是为了生成一个新的对象,那么就以生成临时量的方式来生成新对象,且中间临时量不会生成
const:
const的两个作用,结合中间临时量的第三点:
1.防止通过引用修改实参
2.接收隐式生成的临时量
explicit关键字:
加在构造函数前面,则表示禁止通过此构造函数来 隐式的生成中间变量