拷贝构造函数特点:拷贝构造函数可以使用一个已经存在的对象来初始化另一个同类型的对象,它具有唯一的参数,且该参数为拷贝构造函数所在类类对象的引用。
拷贝构造函数在三种情况下会被调用:
1.一个对象需要通过另一个对象来初始化
2.一个对象以值传递的方式使用
3.一个对象以值传递的方式从函数返回
#include <iostream>
using namespace std;
class Date{
public:
void input();
void output();
Date(Date &date);
Date(int y,int m,int d){
year=y;
month=m;
day=d;
}
private:
int year;
int month;
int day;
};
//在成员函数内可以访问私有变量
void Date::input(){
cout<<"请输入一个日期:";
cin>>year;
cin>>month;
cin>>day;
}
void Date::output(){
cout<<year<<"年"<<month<<"月"<<day<<"日"<<endl;
}
Date::Date(Date &date){
cout<<"拷贝构造函数被调用!"<<endl;
year=date.year+1;
month=date.month;
day=date.day;
}
void func(Date date){
date.output();
}
Date func2(){
Date date(2015,12,15);
return date;
}
int main()
{
//使用d1来初始化d2的值,调用拷贝构造函数
Date d1(2015,12,13);
Date d2(d1);
d2.output();
//主调函数中调用func函数时,需要将实参date3的值传递给形参date,这个过程使用拷贝构造函数来完成
Date d3(2015,12,14);
func(d3);
//一个对象以值传递的方式从函数返回,在func2函数调用完成后,局部对象date就会消亡,所以在实际执行时,编译器会生成一个Date类型的临时对象
//来接收return语句返回的对象值,这个值传递的过程就是通过调用返回类型的拷贝构造函数来实现的
func2().output();
return 0;
}
浅拷贝
#include<iostream>
#include<cstring>
using namespace std;
class Student{
public:
Student();
void setName(char *n);
void outputName();
private:
char *name;
};
<strong>Student::Student(){
name=new char[10];
if(name!=NULL){
strcpy(name,"xiaoming");
}
}</strong>
void Student::setName(char *n){
if(name!=NULL){
strcpy(name,n);
}
}
void Student::outputName(){
cout<<name<<endl;
}
int main()
{
Student s1,s2(s1);
cout<<"s1's name is:";
s1.outputName();
cout<<"s2's name is:";
s2.outputName();
s1.setName("xiaozhang");
cout<<"----after change---"<<endl;
cout<<"s1's name is:";
s1.outputName();
cout<<"s2's name is:";
s2.outputName();
return 0;
}
程序原本打算将s1的name改为"xiaoxin",结果s2的name也跟着改变,原因在于默认的拷贝构造函数只能实现浅拷贝,程序中首先定义了Student类型的对象s1,并使用默认构造函数初始化,初始化时向向系统申请一块堆空间,然后将成员变量name指针指向该空间,当定义s2时,用对象s1初始化,调用的是系统默认的拷贝构造函数,,由于它只实现浅拷贝的功能,只拷贝成员变量的值。结果是s2的成员name指针具有了和s1成员name指针指向同一内存空间。所以修改s1的同时也修改了s2。
深拷贝:
#include<iostream>
#include<cstring>
using namespace std;
class Student{
public:
void setName(char *n);
void outputName();
Student();
Student(Student &stu);
private:
char *name;
};
Student::Student(){
name=new char[10];
if(name!=NULL){
strcpy(name,"XinMing");
}
}
<strong>Student::Student(Student &stu){
name=new char[10];
strcpy(name,stu.name);
}</strong>
void Student::setName(char *n){
if(name!=NULL){
strcpy(name,n);
}
}
void Student::outputName(){
cout<<name<<endl;
}
<pre name="code" class="cpp">int main()
{
Student s1,s2(s1);
cout<<"s1's name is:";
s1.outputName();
cout<<"s2's name is:";
s2.outputName();
s1.setName("xiaozhang");
cout<<"----after change---"<<endl;
cout<<"s1's name is:";
s1.outputName();
cout<<"s2's name is:";
s2.outputName();
return 0;
}
实现深拷贝,拷贝构造函数必须自己来定义。它把资源也重新赋值一次,使得不同的对象拥有不同的资源,但资源的内容是一样的,对于堆来说,就是再开辟一个堆内存,把原来的内容再拷贝到新的空间中。在使用s1初始化s2的时候,为s2的name重新申请了一块堆内存,并将s1拥有的name堆空间中的内容拷贝到s2的内存空间中。