8.7构造函数:
每个对象区别与其他对象的地方主要有两个:①外在的区别是的名称,②内在的区别是对象的名称。C++中,对象的初始化是由一个特殊的成员函数来完成的,称为构造函数。每个类都应该有自己的构造函数,它是类的成员函数。
构造函数必须满足的条件有两个:①构造函数的名字与类的名字相同;②构造函数没有返回值。一般情况下,构造函数有公共的访问属性。
关于构造函数,需要注意:
①对于某个类,可以定义多个同名的构造函数,这些构造函数之间形成函数的重载。
②构造函数的调用是在定义对象的时刻进行的,且调用的具体构造函数根据对象定义的形式来确定。
③如果在定义类时没有定义类的构造函数,编译系统会在编译时自动生成一个默认形式的构造函数,称为默认构造函数。默认构造函数是无参的函数。
8.8析构函数
形式:
Class Student{
public:
~student()
};
它是类的一个成员函数,它的名称是类的名字前加“~”构成,没有返回值。
关于析构函数,需要注意:
①由于它是无参的,名字又唯一,因此析构函数不能进行重载。
②析构函数的调用是在对象的删除的时刻进行的。
③如果没有定义析构函数,系统会自动生成一个,称为默认析构函数。
④默认析构函数只能用来释放对象的成员数据所占用的空间,但不包括堆空间的资源。因此,当构造函数中使用new运算符申请从堆中分配空间时,为了防止内存泄漏,需要具体定义析构函数,而不是使用默认析构函数。
8.9拷贝构造函数
拷贝构造函数是一种特殊的构造函数,其形式参数为本类对象的引用。
其形式Student (Student &pStudent);
常应用与以下3种情况:
①当用一个类的对象去初始化类的另一个对象时,系统会自动调用拷贝构造函数实现拷贝赋值。
②若函数的形参为类的对象,调用函数时,实参赋给形参,系统会自动调用拷贝构造函数实现拷贝赋值。
③当函数的返回值为类的对象时,系统调用拷贝构造函数实现拷贝赋值。
关于拷贝构造函数,需要注意:
①拷贝构造函数首先必须是构造函数,只是该函数要求其形参要多少本类对象的引用。
②若在类定义时没有显示地定义拷贝构造函数,系统会自动生成一个默认的拷贝构造函数,完成将类的成员一一复制的功能。
③拷贝构造函数与其他构造函数形成重载。
8.10浅拷贝和深拷贝
当定义拷贝构造函数时,只是完成一一对应的成员值的简单复制,称其为浅拷贝构造函数。但是,如果类的数据成员包含指针变量,类的构造函数必须使用new运算符为这个指针动态申请堆空间。如果此时还只是使用浅拷贝的方式进行对象的复制。最后,在退出运行时,由于两个对象的指针指向同一个堆空间资源,当调用析构函数先后删除这两个指针的堆空间中的资源时,程序会出错。为了解决此问题,必须定义深拷贝构造函数。
#include<iostream> #include<cstring> using namespace std; class Student{ public: Student(int pId,char* pName,char pSex); ~Student();//析构函数声明 Student(Student &stu);//深拷贝构造函数声明 void printStudent(); private: int id; char* name; char sex; }; Student::Student(int pId,char *pName,char pSex) { cout<<"constructing..."<<endl; id=pId; name=new char[strlen(pName)+1]; if(name!=0) strcpy(name,pName); sex=pSex; } Student::Student(Student& stu)//深拷贝函数 { cout<<"deep copy contructing..."<<endl; id=stu.id; name=new char[strlen(stu.name)+1]; if(name!=0) strcpy(name,stu.name); sex=stu.sex; } Student::~Student() { cout<<"destructing..."<<endl; delete[] name; } void Student::printStudent() { cout<<"id: "<<id<<","<<"name: "<<name<<","<<"sex: "<<sex<<endl; } int main() { Student stu(1,"wang",'M'); Student stu1=stu; stu.printStudent(); stu1.printStudent(); return 0; }