面向对象基础知识2
1、拷贝构造函数和缺省拷贝构造函数
拷贝构造函数的功能:用一个已知对象来初始化一个新创建的同类对象。
ClassName::ClassName([const] ClassName & Obj)
{ 函数体 }
形参Obj是实参对象的引用,即实参对象的别名。const是关键字,如果给出,表示形参Obj在拷贝构造函数的函数体中是对象常量,不能被修改,以保护实参对象。
1 #include<iostream> 2 using namespace std; 3 class Point 4 { 5 int x,y; 6 public: 7 Point(int a=0,int b=0) //缺省构造函数 8 { 9 x=a;y=b; 10 cout<<x<<','<<y<<" 构造函数被调用!"<<endl; 11 } 12 Point(Point &p); //拷贝构造函数原型声明 13 ~Point() 14 { 15 cout<<x<<','<<y<<" Destructor Called."<<endl; 16 } 17 void Show() 18 { 19 cout<<"Point: "<<x<<','<<y<<endl; 20 } 21 }; 22 Point::Point(Point &p) //定义拷贝构造函数 23 { 24 x=p.x;y=p.y; 25 cout<<x<<','<<y<<" 拷贝构造函数被调用!"<<endl; 26 } 27 28 int main() 29 { 30 Point p1(6,8),p2(4,7); 31 Point p3(p1); 32 Point p4=p2; 33 p1.Show(); 34 p2.Show(); 35 p3.Show(); 36 p4.Show(); 37 return 0; 38 }
程序运行结果:
拷贝构造函数的特点:
①函数名与类名相同,因为它也是构造函数,并且该函数不给出返回值类型。
②该函数只有一个参数,必须是本类对象的引用。
③每个类必须有一个拷贝构造函数。如果用户在定义类时没有给出拷贝构造函数,则系统自动产生一个缺省的拷贝构造函数。
注意:如果类的数据成员没有动态申请的数据空间,编程者可以不定义拷贝构造函数,使用系统自动产生的拷贝构造函数就可以了。但是,如果类的数据成员中有动态申请的存储空间,则必须定义拷贝构造函数,否则会出错。
1 #include<iostream> 2 using namespace std; 3 class Student 4 { 5 char *Name; 6 int Age; 7 public: 8 Student(char *namep,int age) 9 { 10 Age=age; 11 if(namep) 12 { 13 Name=new char[strlen(namep)+1]; 14 strcpy(Name,namep); 15 } 16 else 17 Name=NULL; 18 } 19 ~Student() 20 { 21 if(Name) 22 delete [] Name; 23 } 24 void Show() 25 { 26 cout<<Name<<','<<Age<<endl; 27 } 28 }; 29 30 int main() 31 { 32 Student a("George",20); 33 Student b=a; 34 b.Show(); 35 return 0; 36 }
程序结果:
程序自动产生的拷贝构造函数如下:
1 Student::Student(const Student & s) //“浅”拷贝构造函数 2 { 3 Name=s.Name; //直接赋地址值 4 Age=s.Age; 5 }
注意:Name是指针。假定a对象中动态申请并赋值的字符串“George”的起始地址是1000,即a对象的Name值为1000。调用拷贝构造函数时,b对象的Name值被赋值为a对象的Name值,结果两个对象的Name值相同,指向同一存储空间。程序结束时,系统先撤销b对象,调用析构函数将b对象的成员Name指针指向的串空间撤销;然后撤销a对象,由于a的成员Name的指针指向的串空间已经被撤销,再次撤销就出错了。
(1)浅拷贝
简单地把数据成员的值依次赋给新创建对象的数据成员。
(2)深拷贝
如果一个对象有动态申请的存储空间,拷贝构造函数为新对象重新申请同样大小的动态存储空间,并把已知对象动态存储空间中的内容复制到新对象的动态存储空间中。
深拷贝构造函数:
1 Student::Student(const Student & s) //“深”拷贝构造函数 2 { 3 Age=s.Age; 4 if(s.Name) 5 { 6 Name=new char[strlen(s.Name)+1]; 7 strcpy(Name,s.Name); 8 } 9 else 10 Name=NULL; 11 }