复制控制
在现实中有很多的类都有相似的地方,我们需要处理关于类的复制问题,我们把关于类复制的复制构造函数和赋值操作符重载统称为复制控制。
复制构造函数
直接来看例子,用例子讲解
//面向对象进阶
//作者:分解机226
#include <iostream>
using namespace std;
class BOLI
{
public:
BOLI(int aa) :a(aa) {}
BOLI(const BOLI& boli) :a(boli.a)
{
cout << "BOLI的拷贝构造函数被调用" << endl;
}
private:
int a;
};
BOLI test(BOLI boli)
{
cout << "test函数开始执行" << endl;
return boli;
}
int main()
{
BOLI boli(2);
cout << "显示调用复制构造函数!" << endl;
BOLI boli2(boli);
cout << "test函数调用前" << endl;
test(boli2);
cout << "test函数调用后" << endl;
BOLI boliArr[3] = { boli,boli,boli2 };
return 0;
}
在本例中BOLI的复制构造函数被调用了6次
第一次是对boli传参的显示调用
第二次在test函数体之前
第三次发生在test函数体结束之前
最后三次是在初始化列表初始化数组的时候
下面我们来看看复制构造函数的具体语法,在上面的BOLI中复制构造函数的参数类型是“const BOLI &boli”,是因为复制不需要改变原来的对象,只是拿来当作范本而已,我们继续看代码例子
//面向对象进阶
//作者:分解机226
#include <iostream>
using namespace std;
class BOLI
{
public:
BOLI(int aa) :a(aa) {}
BOLI(const BOLI boli) :a(boli.a)//在这里对于boli的处理是没有使用地址引用,而是使用的是按值传参
{
cout << "BOLI的拷贝构造函数被调用" << endl;
}
private:
int a;
};
int main()
{
BOLI boli(2);
cout << "显示调用复制构造函数" << endl;
BOLI boli2(boli);
return 0;
}
出现这样的情况是因为按值传参的复制构造函数在参数传递的时候会再次调用复制构造函数,也就是说是按值传参的话复制构造函数就会一直循环下去。
合成的复制构造函数
//面向对象进阶
//作者:分解机226
#include <iostream>
using namespace std;
class BOLI
{
public:
BOLI(int aa,int bb):a(aa),b(bb){}
void printvalu()
{
cout << "a的值" <<a<< endl;
cout << "b的值" <<b<< endl;
}
private:
int a;
int b;
};
BOLI test(BOLI boli)
{
return boli;
}
int main()
{
BOLI boli(520, 1314);
boli.printvalu();
cout << "调用test函数" << endl;
test(boli).printvalu();//让test返回副本对象调用函数
return 0;
}
BOLI的定义中没有声明任何的复制构造函数,在test()函数在传参和返回的时候需要复制构造函数,编译器就会自动的合成一个。
//面向对象进阶
//作者:分解机226
#include <iostream>
using namespace std;
class BOLI
{
public:
BOLI(int v):val(v){}
int getval() { return val; }
private:
int val;
};
class DB
{
DB(BOLI cp,BOLI *cpPtr):boli(cp),boliptr(cpPtr){}
void print()
{
cout << "boli的val是" << boli.getval() << endl;
cout << "boliptr的地址是" << boliptr << endl;
cout << "boliptr指向对象的值" << boliptr->getval() << endl;
}
private:
BOLI boli;
BOLI* boliptr;
};
DB test(DB db)
{
return db;
}
int main()
{
BOLI boli1(520);
BOLI boli2(1314);
DB db(boli1, &boli2);
db.print();
cout << "调用test" << endl;
test(db).print();
return 0;
}
我们可以看到合成的复制构造函数对于指针只是简单的复制了地址,而两个对象中boliptr地址相同,指向的是同一个对象,这样不仅没有达到复制的效果,而且如果boliptr指向的对象是动态分配的,系统在调用第二次析构函数的时候将会出现boliptr的指向对象已经被释放,我们把这种仅仅复制指针地址的复制叫做浅复制
有浅复制就有深复制
//面向对象进阶
//作者:分解机226
#include <iostream>
using namespace std;
class Component
{
public:
Component(int v):val(v){}
int getval() { return val; }
private:
int val;
};
class Myclass
{
Myclass(Component cp,Component *cpPtr):comp(cp),compPtr(cpPtr){}
Myclass(const Myclass& myclass) :comp(myclass.comp) {
this->compPtr = new Component(*myclass.compPtr);
}
~Myclass()
{
delete compPtr;
}
void print()
{
cout << "boli的val是" << comp.getval() << endl;
cout << "boliptr的地址是" << compPtr << endl;
cout << "boliptr指向对象的值" << compPtr->getval() << endl;
}
private:
Component comp;
Component* compPtr;
};
Myclass test(Myclass myclass)
{
return myclass;
}
int main()
{
Component comp1(520);
Component comp2(1314);
Myclass myclass1(comp1, &comp2);
myclass1.print();
cout << "调用test" << endl;
test(myclass1).print();
return 0;
}
深浅复制的区别在于深复制多了一个自定义的构造函数和析构函数