默认复制构造函数
-
默认复制构造函数的原型声明(浅复制):<类名>(const <类名>& < obj >)
-
系统生成的默认复制构造函数,它的所做工作大体如下:
{
mem1=obj.mem1;
mem2=obj.mem2;
mem3=obj.mem3;
}
默认复制构造函数的功能是把已知对象的每个数据成员的值依次赋值到新定义对象的对应成员中,不做其它处理. -
那么这里就存在一个问题:
-----在创建对象bookCopy时,调用了系统默认生成的复制构造函数.默认的复制构造函数将book对象成员的值依次赋给bookCopy中的成员,导致bookCopy对象中的指针变量bookName,author和book对象中的指针变量bookName,author分别指向了同一块存储空间.当一个对象的生存期结束而调用析构函数释放内存空间后,另一个对象中的指针变量悬空,当再次访问它时(调用析构函数释放其指向的空间),出现了内存访问错误. -
这就是默认复制构造函数浅复制中存在的隐形问题。(虽然我运行后并没有报错,但存在隐形问题)
#include <iostream>
using namespace std;
class Book{
private:
char *bookName;
char *author;
float price;
public:
void print();
Book(const char *bookName1,const char *author1,float price1);
~Book();
};
int main()
{
Book book("《平凡的世界》","路遥",98.20);
Book bookCopy(book);
book.print();
bookCopy.print();
return 0;
}
void Book::print()
{
cout<<bookName<<'\t'<<author<<'\t'<<price<<endl;
}
Book::Book(const char *bookName1,const char *author1,float price1)
{
bookName=new char[strlen(bookName1)+1];
author=new char[strlen(author1)+1];
strcpy(bookName,bookName1);
strcpy(author,author1);
price=price1;
}
Book::~Book()
{
delete [] bookName;
delete [] author;
}
自定义复制构造函数
#include <iostream>
using namespace std;
class Book{
private:
char *bookName;
char *author;
float price;
public:
void print();
Book(const char *bookName1,const char *author1,float price1);
//这里构造函数重载了
Book(const Book& myCopy); //我们自定义的复制构造函数
~Book();
};
int main()
{
Book book("《平凡的世界》","路遥",98.20);
Book bookCopy(book);
book.print();
bookCopy.print();
return 0;
}
void Book::print()
{
cout<<bookName<<'\t'<<author<<'\t'<<price<<endl;
}
Book::Book(const char *bookName1,const char *author1,float price1)
{
bookName=new char[strlen(bookName1)+1];
author=new char[strlen(author1)+1];
strcpy(bookName,bookName1);
strcpy(author,author1);
price=price1;
}
//自定义的复制构造函数
Book::Book(const Book& myCopy)
{
//这里动态分配的空间也同样"深复制"了
bookName=new char[strlen(myCopy.bookName)+1];
strcpy(bookName,myCopy.bookName);
author=new char[strlen(myCopy.author)+1];
strcpy(author,myCopy.author);
price=myCopy.price;
}
Book::~Book()
{
delete [] bookName;
delete [] author;
}
- 当一个类有指针成员(可能会拥有资源,如堆内存),这时使用默认的复制构造函数,可能会出现两个对象拥有同一个资源的情况,当对对象析构时,一个资源会经历两次释放,因此程序会出错。
- 默认的复制构造函数只实现了成员之间数值的“浅复制”,并没有复制资源。如果存在资源问题,必须显示定义复制构造函数,完成“深复制”工作。
- 这里资源都是指堆资源,不仅仅是堆资源,当类中涉及需要打开文件,占有硬件设备服务等也需要深复制。同理,如果类中需要析构函数来释放堆资源时,则类也需要显示定义一个可以释放堆资源的析构函数。不过它们都不需要显示调用。