1拷贝构造函数
拷贝构造函数是一种特殊的构造函数,它由编译器调用来完成一些基于同一类的其他对象的构建及初始化。其唯一的参数(对象的引用)是不可变的(const类型)。此函数经常用在函数调用时用户定义类型的值传递及返回。拷贝构造函数要调用基类的拷贝构造函数和成员函数。一般来说只包含类类型和内置类型(不是指针类型)成员的类,无需自定义复制构造函数。
合成复制构造函数相当于一个每个数据成员都在构造函数初始化列表中初始化的构造函数,类是下面 类X
class X
{
public:
string isbn;
int x;
double y;
};
合成复制构造函数类似下面这种构造函数(参数是 const 引用 类)
X::X(const X& a):isbn(a.isbn),x(a.x),y(a.y){}
浅拷贝和深拷贝
在某些状况下,类内成员变量需要动态开辟堆内存,如果实行位拷贝,也就是把对象里的值完全复制给另一个对象,如A=B。这时,如果B中有一个成员变量指针已经申请了内存,那A中的那个成员变量也指向同一块内存。这就出现了问题:当B把内存释放了(如:析构),这时A内的指针就是野指针了,出现运行错误。
深拷贝和浅拷贝可以简单理解为:如果一个类拥有资源,当这个类的对象发生复制过程的时候,资源重新分配,这个过程就是深拷贝,反之,没有重新分配资源,就是浅拷贝。下面举个深拷贝的例子。
来看一下一个例子:
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
class MyString
{
private:
char *m_data;
int data;
public:
//普通构造函数
MyString(const char * str = NULL,const int s = 0);
//拷贝构造函数
//MyString(const MyString & other);
//析构函数
~MyString();
//赋值函数
//MyString & operator = (const MyString &other);
};
MyString::MyString(const char *str,const int s)
{
data = s;
cout << "constructing string by " << str << endl;
if(str == NULL)
{
m_data = new char[1];
*m_data = '\0';
}
else
{
int len = strlen(str);
m_data = new char[len + 1];
strcpy(m_data,str);
}
}
MyString::~MyString()
{
delete m_data;
}
int main()
{
MyString s1("hehe");
MyString s = s1;
}
这个时候执行会出现错误。因为类中拥有资源。在复制的过程中没有重新分配资源。所以在析构的时候删除了两次空间。
我们可以打印一下 两个类中 m_data字符串的起始地址看一下:
在函数中添加一个打印函数:
void MyString::PrintAdd()
{
cout <<"s地址为:" <<static_cast<const void *> (m_data) << endl;
}
看一下打印结果:
这里可以看到类中两个 字符串的起始地址是一样的,就是指向同一片空间。即在复制的时候直接复制指针的值,而不是重新分配空间,所以析构的时候会析构两次出现错误。So这是浅拷贝。
自定义拷贝构造函数:
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
class MyString
{
private:
char *m_data;
int data;
public:
//普通构造函数
MyString(const char * str = NULL,const int s = 0);
//拷贝构造函数
MyString(const MyString & other);
//析构函数
~MyString();
//赋值函数
//MyString & operator = (const MyString &other);
};
MyString::MyString(const char *str,const int s)
{
data = s;
cout << "constructing string by " << str << endl;
if(str == NULL)
{
m_data = new char[1];
*m_data = '\0';
}
else
{
int len = strlen(str);
m_data = new char[len + 1];
strcpy(m_data,str);
}
}
MyString::MyString(const MyString & other)
{
cout << "constructing by other MyString " << other.m_data << endl;
int length = strlen(other.m_data);
m_data = new char[length + 1];
strcpy(m_data,other.m_data);
}
MyString::~MyString()
{
cout <<"destructing \n" ;
delete m_data;
}
int main()
{
MyString s1("hehe");
MyString s = s1;
}
执行结果:
拷贝构造函数中对 类中对象所占用的空间重新分配。所以析构的时候没有问题。
如何禁止复制构造函数:
1.将复制构造函数声明为private,则不允许用户代码复制该类类型的对象。但是 类的友元和成员 还是可以复制的。如何让这两个也禁止复制呢。
2声明一个private复制构造函数,但是不定义 就解决了上诉问题。