复制构造函数是一个特殊的构造函数,无论何时创建一个新对象,并且使用同一类的另一个对象对它进行初始化时,都会调用该构造函数。
关于复制构造函数的话题有很多。
实际上,这些特性用的好就叫特性,用不好就是缺陷了。
1.赋值
属于同一类的对象赋值给另外一类对象。
比如有一个类,名叫A,
现在 A aa;
A bb;
aa = bb;
这就是赋值,两个类都已经存在,且进行了初始化(这里是默认的),这样aa和bb的内容就是一样的,bb把自己的内容赋给了aa
但是,如果是下面这样,就不是赋值了
A aa;
A bb = aa;
这里就会调用复制构造函数。这里会有很多问题,比如深拷贝和浅拷贝。指针指向问题。所以需要深入了解复制构造函数。
2.2.默认复制构造函数
如果没有显式的创建创建一个构造函数,那么编译器就会自动调用一个默认的复制构造函数。默认构造函数会按照成员赋值的方式,将现有对象的数据复制到新对象中。
#include <iostream>
#include<string>
using namespace std;
class Address{
private:
string street;
public:
//无参构造函数
Address(){street = " ";cout<<"无参"<<endl;}
//有参构造
Address(string st){ street = st;cout<<"有参"<<endl;}
//获取street
string getStreet() const {return street;}
};
int main(int argc, char** argv) {
Address mary("beijing");
//这里会调用复制构造函数
Address mike = mary;
//输出mike和mary此刻的地址
cout<<mike.getStreet()<<endl;
cout<<mary.getStreet()<<endl;
//改变mary的地址不会影响到mike的地址
mary =Address( "shanghai");
cout<<mike.getStreet()<<endl;
cout<<mary.getStreet()<<endl;
return 0;
}
有参
beijing
beijing
有参
beijing
shanghai
3.默认构造函数的缺陷。
比如存在指针的时候。直接复制给另一个对象,二者会同时指向一个地址,导致牵一发动全身
#include <iostream>
#include<iomanip>
using namespace std;
class NumberArray{
private:
double* aPtr;
int arraySize;
public:
NumberArray(int size,double value);
void print() const;
void setValue(double value);
};
NumberArray::NumberArray(int size,double value){
arraySize = size;
aPtr = new double [arraySize];
setValue(value);
}
void NumberArray::setValue(double value){
int index;
for(index = 0;index < arraySize;index++)
aPtr[index] = value;
}
void NumberArray::print() const{
int index = 0;
for(index = 0;index < arraySize;index++)
cout<<aPtr[index]<<" ";
cout<<endl;
}
int main(int argc, char** argv) {
NumberArray first(3,10.5);
NumberArray second = first;
cout<<setprecision(2)<<fixed<<showpoint;
first.print();
second.print();
//改变second的值,会发现first也跟着改变了。
second.setValue(3.14);
first.print();
second.print();
return 0;
}
这是做了一个double型的数组,用指针来管理这个数组。如果指向同一个空间,那么在后面用析构函数的时候,就可能造成内存泄漏,删除同一片空间,所以必须自己定义构造函数。
3.自定义一个复制构造函数
类名(类名&)
复制构造函数应该为新的对象分配新的空间。
#include <iostream>
#include<iomanip>
using namespace std;
class NumberArray{
private:
double* aPtr;
int arraySize;
public:
NumberArray(int size,double value);
NumberArray(const NumberArray&);
~NumberArray();
void print() const;
void setValue(double value);
};
NumberArray::NumberArray(int size,double value){
arraySize = size;
aPtr = new double [arraySize];
setValue(value);
}
NumberArray::NumberArray(const NumberArray& obj){
this->arraySize = obj.arraySize;
this->aPtr = new double[this->arraySize];
int index;
for(index = 0;index < this->arraySize;index++)
this->aPtr[index] = obj.aPtr[index];
cout<<"copy\n";
}
NumberArray::~NumberArray(){
if(this->arraySize > 0)
delete [] this->aPtr;
}
void NumberArray::setValue(double value){
int index;
for(index = 0;index < arraySize;index++)
aPtr[index] = value;
}
void NumberArray::print() const{
int index = 0;
for(index = 0;index < arraySize;index++)
cout<<aPtr[index]<<" ";
cout<<endl;
}
int main(int argc, char** argv) {
NumberArray first(3,10.5);
NumberArray second = first;
cout<<setprecision(2)<<fixed<<showpoint;
cout<<"first:\n";
first.print();
cout<<"second:\n";
second.print();
second.setValue(3.14);
cout<<"first:\n";
first.print();
cout<<"second:\n";
second.print();
NumberArray third(3,1.1);
cout<<"third:\n";
third = first;//实际这里也会造成两次删除同一内存,需要重载运算符
third.setValue(8.88);
third.print();
first.print();
return 0;
}
4.复制构造函数被调用的情况。
函数如果是按值传递对象,就会调用复制构造函数
(1)在同一个类中。用一个类去初始化另一个类。
(2)函数的形参是类
(3)函数返回值是类
函数的形参和返回值是类的引用,则不会调用复制构造函数。
这是因为这些调用产生一个临时对象的副本。
可以用上面的代码自己测试