拷贝构造函数 :
1概念
拷贝构造函数只有单个形参,该形参是对本类类型对象的引用(常用const 修饰),
使用已存在的类类型的对象创建新对象时,编译器自动调用该函数。
eg:
假如 Claa A{
public:A(const A& a){}
private :
int a;},
A a ,
A b(a);
2 特征
1 只有一个参数: 引用传参,传值方式将会无限递归(Why)
传值无限递归原因:传值时拷贝构造函数的形参将会拷贝传来的值,也是一个拷贝构造同时也是一个拷贝相当于A b(a);因为类并没有正确实现引用,所以将在形参接收这里无限递归下去。
另外,写成传值编译器将会报错
2 拷贝构造函数是构造函数的一个重载形式,(言下之意,构造函数还有别的函数重载形式)
3 若未进行显式地定义拷贝构造函数,编译器将隐式地生成一个拷贝构造函数,。今天我来补充一下,另一个构造的重载:C++11 提出的引用构造(右值引用) eg: string(string&& s )
4 .既然编译器能自己生成默认的拷贝构造函数,那我们还要自己定义吗?
答案是 肯定的。
理由:编译器并不知道我们的类中是怎样的成员,有没有多次使用用一个类对象定义拷贝构造函数,假如说我们在类中 并没有申请(管理)内存空间,那么出类时,析构函数将会正常的销毁类中的成员(空间资源),释放内存。 但是, 请你想一想,假如你的类中 申请了空间(管理了内存空间),而你申请的空间被拷贝构造函数使用 (换句话说,就是假如拷贝构造函数使用了你申请的内存空间,并拷贝出了多个类 类型的对象),这会发生什么?? 这会导致你申请的空间被同时多个类类型对象共用(换句话说,多个类类型对象指向同一空间(同一对象)),而析构函数会销毁你的所有成员,导致同一申请的空间释放多次,这当然不行了!!!
所以,我们显式地写个拷贝构造函数是很有必要的!(目前我能力还不行,但是道理我懂了,加油)
以下代码为什么会崩掉?留待以后回来看看
#include"iostream"
#include"string.h"
#include"stdio.h"
#include "windows.h"
using namespace std;
class String
{
public :
// 拷贝构造函数
String(const char* str = "Jack")
{
_str = (char*)malloc(strlen(str) + 1);
strcpy(_str, str);
}
//析构函数
~String()
{
cout <<"~String()"<< endl;
//printf("%s","~String()");
free(_str);
}
private:
char * _str;
};
int main(void)
{
String s1("hello");//调用编译器默认生成的构造函数
String s2(s1);
system("pause");
return 0;
}
2 赋值运算符重载
概念:什么是赋值运算符重载?
赋值运算符重载就是:编译器本来不支持该类型的运算,但是用户想实现,所所以产生这个函数。
运算符重载是不是听着就很不一样??
它也是一种函数重载。
函数格式 : 返回值类型 + operate +运算符(参数列表){函数体}
特征: operate 关键字后边 + 运算符符号
注意: 1 不能自己创建新的运算符,运算符就是运算符,不是个别人定义的
2 参数列表必须至少有一个 枚举类型或者类类型的对象
3 运算符的语义不允许更改 eg: 外部为 operate+(参数列表){return a-b;}
这样是错误的!
4 若为类的成员的 (重载)函数,参数还有一个隐藏的this指针,即参数数量+1