(3) 当函数的返回值是对象,函数执行完成,返回调用者时。
// … Coord fun2() { Coord p1(10,30); return p1; } // 函数的返回值是对象 main() { Coord p2; P2=fun2(); // 函数执行完成,返回调用者时,调用拷贝构造函数 return 0; } 3.4 浅拷贝和深拷贝所谓浅拷贝,就是由缺省的拷贝构造函数所实现的数据成员逐一赋值,若类中含有指针类型数据, 则会产生错误。
为了解决浅拷贝出现的错误,必须显示地定义一个自己的拷贝构造函数,使之不但拷贝数据成员,而且为对象1和对象2分配各自的内存空间,这就是所谓的深拷贝。
例2.23 浅拷贝例子 #include<iostream.h> #include<string.h> class Student { public: Student(char *name1,float score1); ~Student(); private: char *name; // 学生姓名 float score; // 学生成绩 }; Student∷Student(char *name1,float score1) { cout<<"Constructing..."<<name1<<endl; name=new char[strlen(name1)+1]; if (name !=0) { strcpy(name,name1); score=score1; } } Student∷~Student() { cout<<"Destructing..."<<name<<endl; name[0]='\0'; delete name; } void main() { Student stu1("liming",90); // 定义类Student的对象stu1 Student stu2=stu1; // 调用缺省的拷贝构造函数 } Constructing... liming Destructing... liming Destructing... 浅拷贝示意图 例2.24 深拷贝例子 #include<iostream.h> #include<string.h> class Student { private: char *name; // 学生姓名 float score; // 学生成绩 public: Student(char *name1,float score1); Student(Student& stu); ~Student(); }; Student∷Student(char *name1,float score1) { cout<<"constructing..."<<name1<<endl; name=new char[strlen(name1)+1]; if (name !=0) { strcpy(name,name1); score=score1; } } Student∷Student(Student& stu) { cout<<"Copy constructing..."<<stu.name<<endl; name=new char[strlen(stu.name)+1]; if (name !=0) { strcpy(name,stu.name); score=stu.score; } } Student∷~Student() { cout<<"Destructing..."<<name<<endl; name[0]='\0'; delete name; } void main() { Student stu1("liming", 90); // 定义类Student的对象stu1, Student stu2=stu1; // 调用自定义的拷贝构造函数 } Constructing…liming Copy constructing…liming Destructing…liming Destructing…liming 深拷贝示意图 4. 析构函数析构函数也是一种特殊的成员函数。它执行与构造函数相反的操作,通常用于撤消对象时的一些清理任务,如释放分配给对象的内存空间等。
析构函数有以下一些特点:① 析构函数与构造函数名字相同,但它前面必须加一个波浪号(~);
② 析构函数没有参数,也没有返回值,而且不能重载。因此在一个类中只能有一个析构函数;
③ 当撤消对象时,编译系统会自动地调用析构函数。 如果程序员没有定义析构函数,系统将自动生成和调用一个默认析构函数,默认析构函数只能释放对象的数据成员所占用的空间,但不包括堆内存空间。
例2.25 重新说明类Date #include <iostream.h> class Date{ public: Date(int y,int m,int d); // 构造函数 ~Date(); // 析构函数 void setDate(int y,int m,int d); void showDate(); private: int year, month, day; }; Date::Date(int y,int m,int d) // 构造函数的实现 { cout<<"constructing..."<<endl; year=y;month=m; day=d; } Date::~Date() // 析构函数的实现 { cout<<"destruting..."<<endl; } void Date::setDate(int y,int m,int d) { year=y;month=m;day=d; } inline void Date::showDate() { cout<<year<<"."<<month<<"."<<day<<endl; } void main() { Date date1(1998,4,28); // 定义类Date的对象date1, // 调用date1的构造函数,初始化对象date1 cout<<"Date1 output1:"<<endl; date1.showDate(); // 调用date1的showDate(),显示date1的数据 date1.setDate(2002,11,14); // 调用date1的setDate(), // 重新设置date1的数据 cout<<"Date1 output2:"<<endl; date1.showDate(); // 调用date1的showDate(),显示date1的数据 } 析构函数被调用的两种情况1) 若一个对象被定义在一个函数体内,当这个函数结束时,析构函数被自动调用。
2) 若一个对象是使用new运算符动态创建,在使用delete释放时,自动调用析构函数。
每个类必须有一个析构函数。
若没有显式地为一个类定义析构函数,编译系统会自动地生成一个缺省的析构函数