在C++中,如果一个类并没有提供一些必要的操作,而又有人在使用这个类(比如构造、赋值等操作),编译器会根据需要为这个类偷偷加上默认构造函数、析构函数、拷贝构造函数、赋值运算符重载。
但是,当一个类包含指针或者引用成员的时候,编译器默认生成的函数就不怎么管用了——因为它们执行的是浅拷贝。此处就以String类为例,实现一下相关的四个函数.
原型如下:
/***************
* String.h
**************/
#ifndef _STRING_H_
#define _STRING_H_
#include <windows.h>
class String
{
public:
String(const char *str = NULL); // 普通构造函数
String(const String& other); // 拷贝构造函数
~String(void); // 析构函数
String& operator = (const String& other); // 赋值函数
private:
char *m_pszData; // 用于保存字符串
};
#endif //_STRING_H_
分析:
【普通构造函数】需要自行分配一块内存,来保存参数所指向的字符串,同时需要考虑参数为空的情况。
【拷贝构造函数】C++允许拷贝构造函数访问参数对象的私有成员,所以只需‘分配 + 拷贝’即可。
【析构函数】需要回收私有指针成员指向的内存。
【赋值操作符重载】操作同拷贝构造函数类似。但需要注意的是:由于自身已经被构造,所以需要先回收指针成员所指向的内存,再重新进行‘分配 + 拷贝’。而这又引入了一个问题:如果当前进行的操作是自赋值,就不能进行回收,否则会造成数据丢失,需要单独判断处理。
代码如下:
/********************
* String.cpp
*******************/
#include "String.h"
// 普通构造函数.
String::String(const char *str /*= NULL*/)
{
if(NULL == str)
{
m_pszData = new char('\0');
}
else
{
int len = strlen(str) + 1;
m_pszData = new char[len];
strcpy(m_pszData, str);
}
}
// 拷贝构造函数.
String::String(const String &other)
{
int len = strlen(other.m_pszData) + 1;
m_pszData = new char[len];
strcpy(m_pszData, other.m_pszData);
}
// 析构函数.
String::~String(void)
{
delete[] m_pszData;
}
String & String::operator = (const String& other)
{
// 由于‘回收 + 拷贝’的做法,基于‘非自赋值’的假设.
// 此处应单独处理自赋值的情况.
if(this == &other)
{
return *this;
}
// 对m_pszData重新赋值之前,回收它当前指向的内存.
delete[] m_pszData;
// 拷贝.
int len = strlen(other.m_pszData) + 1;
m_pszData = new char[len];
strcpy(m_pszData, other.m_pszData);
return *this;
}
//简单测试.
int main()
{
char* psz1 = "Yes.";
char* psz2 = "Nope.";
String string1(psz1);
String string2(psz2);
String string3(string2);
String* string4 = new String(psz2);
String* string5 = new String(string2);
string2 = string1;
string3 = string2;
*string4 = string3;
*string5 = *string4;
delete string4;
delete string5;
return 0;
}
可在main函数中加入断点进行调试,观察各String对象的变化情况。
======================End============================