假设你重新定义String类如下:
class String{ };
这就如同你写下了这样的代码:
class String
{
String() {....} //default构造函数
String(const String& rhs) {....} //copy构造函数
~String() {....} // 析构函数 为非non-virtual 可参考item:Declar destructors virtual in polymorphic base classes。
String& operator=(const String& rhs) {....} // copy assignment操作符
};
所以我们定义一个如上的空类后、也可以如下方式使用而不提示错误:
String str1; //调用default 构造函数
String str2(str1); //调用copy构造函数
str2 = str1; //调用copy assignment操作符
主要考虑copy构造函数和copy assignment操作符 两个函数
编译器创建的版本只是单纯的将来源对象的每一个non-static成员变量拷贝到目标对象。这是所谓的浅复制。
然而用默认的这些函数存在着很大的隐患,如下:
当我们的成员变量是指针的时候、例如下面一个类:
class A
{
public:
A(const char* str){p = str;}
private:
char* p;
};
调用以下代码:
A a1(“I am a student”);
A a2;
a2 = a1;
我们看看会出什么情况、运行代码后、编译器会为类A自动生成copy assignment操作符、执行如下代码:a2.p =a1.p 这将会产生如下问题:
1、a2.p所指的原有的内存没有释放、造成内存泄漏。
2、a2.p、a1.p 指向同一块内存、如有一方变动者都会影响另一方。
3、在对象析构时、p所指的内存将释放两次。
这个时候需要我们自己重新对这些函数进行定义、实现对指针所指向对象的克隆(这是所谓的深复制)
这个时候就需要我们自己为这四大函数重新进行定义:
还是以String 为例:
#include <iostream>
using std::ostream;
using std::endl;
using std::cout;
class String
{
public:
friend ostream& operator << (ostream& os, const String& s);
String(const char *str = NULL); //constructor
String(const String &other); //copy constructor
~String(void); //destructor
String& operator = (const String &other); // operator =
private:
char* m_data;
};
ostream& operator<<(ostream& os, const String& s)
{
os << s.m_data;
return os;
}
String::String(const char *str)
{
if(str == NULL)
{
m_data = new char[1];
if(!m_data)
{
cout << "memory distribute error/n";
exit(1);
}
}
else
{
m_data = new char[strlen(str) + 1];
strcpy(m_data, str);
}
}
String::String(const String& other) //copy constructor
{
m_data = new char[strlen(other.m_data) + 1];
strcpy(m_data, other.m_data);
}
String::~String(void) //destructor
{
delete []m_data;
}
String & String::operator = (const String &other) //operator =
{
if(this == &other)
return* this;
delete [] m_data;
m_data = new char[strlen(other.m_data) + 1];
strcpy(m_data, other.m_data);
return* this;
}
int main()
{
String a("I am a student"); // call constructor
String b(a); //call copy constructor
String c = a; //call operator =
cout << a << ' ' << b << ' ' << c << endl;
return 0;
}
最后请记住:
编译器可以暗自为class创建default构造函数、copy构造函数、copy assignment操作符、以及析构函数。在成员变量中存在指针的时候,一定要自己重新定义这四大函数。