定义一个类
class CTest {
public:
int m_a;
CTest(int m_a):m_a(0){
}
};
在主函数中定义对象
CTest tes1(1);
CTest tes2 = 5;//我们发现这种定义对象的方式不符合常理,这里其实是发生了隐式类型转换(用到了编译器默认的转换构造函数)
转换构造函数就是可以发生隐式类型转换的构造函数
我们可以用这个关键字修饰构造函数,禁止发生隐式类型转换,必须手动显示传递
代码如下
class CTest {
public:
int m_a;
explicit CTest(int a) :m_a(a) {
}
};
在主函数定义对象
CTest tes2 = 4; //禁止隐式转换,不可用
CTest tes5(2);//必须显示传递
定义一个类
class CTest {
public:
int m_a;
CTest(int a) :m_a(a) {
}
};
在主函数中定义对象
CTest tes1(3);
CTest tes2(tes1);//我们发现这种定义对象的方式不符合常理,这里其实是发生了拷贝(用到了编译器默认的拷贝构造函数)
拷贝构造函数,函数名为:当前类名,参数为 const类对象的引用
函数体代码:编译器提供的,函数代码不为空,形参中对象的成员依次给this对象中的成员做初始化操作,一旦我们手动重构了拷贝构造函数,编译器就不会提供默认的拷贝构造函数了
//如下我们自己手动重构一个拷贝构造函数
CTest(CTest& tes) :m_a(tes.m_a){}
浅拷贝:编译器默认提供的拷贝构造函数,是一个浅拷贝。(上面的拷贝构造函数也是一个浅拷贝)
浅拷贝问题:在类中存在指针成员并申请堆区空间时,拷贝的构造函数只是地址之间的拷贝,会导致多个对象中的指针成员指向了同一块空间,在析构函数回收时,同一块空间被回收多次,程序异常
如下代码定义对象时就会出现问题
class CTest {
public:
int m_a;
int* p;
CTest(int a):m_a(a),p(new int(7)) {
}
//浅拷贝
CTest(CTest& tes) :m_a(tes.m_a),p(tes.p) {
cout << __FUNCTION__ << endl;
}
~CTest() {
delete p;
p = nullptr;
}
};
这时我们就可以用深拷贝来解决这个问题
深拷贝我们需要自己手动重构拷贝构造函数
解决:为当前对象中的指针单独开辟一块属于自己的空间,并将值也拷贝过来,这样就不会多次回收同一块空间了,问题得到了解决
代码如下
class CTest {
public:
int m_a;
int* p;
CTest(int a):m_a(a),p(new int(7)) {
}
//深拷贝
CTest(CTest& tes) :m_a(tes.m_a),p(new int(*tes.p)) {}
~CTest() {
delete p;
p = nullptr;
}
};
我们在调用时函数要注意,如果参数是类的对象话,函数参数尽量使用引用、指针,避免值传递,这样就不会发生拷贝,就不会出现浅拷贝问题(当然如果非要用的话,注意要自己重构一个拷贝构造函数—深拷贝)
代码如下
void fun(CTest& tes){}
定义一个类
class Ctest {
public:
int m_a;
explicit Ctest(int a):m_a(a)){}
};
在主函数中定义对象
Ctest tst1(4);
Ctest tst2(3);
tst2 = tst1; //我们发现这里不符合常理,正常来说对象与对象之间不能直接用对象名赋值,其实这里是用到了编译器默认的operator=
在空类中,默认会提供下面的函数,参数为const 当前类对象引用(同拷贝构造一样),返回类型为当前类对象的引用)
编译器默认提供的这个函数函数体代码,形参中对象的成员依次给this对象中的成员做赋值操作,一旦我们手动重构了这个函数,编译器就不会提供默认的了
我们重构一个operator= 函数来模拟一下这个过程
代码如下
Ctest& operator=(const Ctest& tst1) {
this->m_a = tst1.m_a;
return *this;
}
编译器默认的是浅拷贝,会有浅拷贝问题
如下代码
class Ctest {
public:
int m_a;
int* m_p = nullptr;
explicit Ctest(int a):m_a(a), m_p(new int(5)){}
//浅拷贝
Ctest& operator=(const Ctest& tst1) {
this->m_a = tst1.m_a;
return *this;
}
~Ctest() {//会回收多次相同的空间
delete m_p;
m_p = nullptr;
}
};
所以这里我们需要手动实现深拷贝来解决这个问题
代码如下
class Ctest {
public:
int m_a;
int* m_p = nullptr;
explicit Ctest(int a):m_a(a), m_p(new int(5)){}
//深拷贝
Ctest& operator=(const Ctest& tst) {
if (this != &tst) {
this->m_a = tst.m_a;
if (tst.m_p) {
//将代码进行优化,用三目运算符的写法代替if else的写法
/*if (this->m_p) {
*this->m_p = *tst1.m_p;
}
else {
this->m_p = new int(*tst1.m_p);
}
}*/
//三目运算符
this->m_p ? *this->m_p = *tst.m_p : (this->m_p = new int(*tst.m_p),0);
}
else {
if (this->m_p) {
delete m_p;
m_p = nullptr;
}
}
}
return *this;
}
~Ctest() {//会回收多次相同的空间
delete m_p;
m_p = nullptr;
}
};