/***************************************************************
题目:如下为类型CMyString的声明,请为该类型添加赋值运算符函数。
class CMyString
{
public:
CMyString(char* pData = NULL);
CMyString(const CMyString& str);
~CMyString(void);
private:
char* m_pData;
};
***************************************************************/
#include<stdio.h>
#include<string.h> //当使用strcpy、strlen、strcat函数时,需要加头文件<string.h>
class CMyString
{
public:
CMyString(char* pData = NULL);
CMyString(const CMyString& str);
~CMyString(void);
CMyString& operator=(const CMyString& str);//赋值操作符返回类型应为该类型的引用,参数应为常量引用
friend void myStrPrint(const CMyString& str);
private:
char* m_pData;
};
CMyString::CMyString(char* pData)
{
if(NULL == pData) //注意参数为指针时,看有没有必要判断是否为NULL
{
m_pData = new char[1]; //注意new的用法,p_var = new type [size];
m_pData[0] = '\0'; //注意字符串结束符号为'\0',而不是'/0'
}
else{
m_pData = new char [strlen(pData) + 1];//注意字符串内存度需要包括字符串结束符
strcpy(m_pData, pData);//注意strcpy的用法
}
}
CMyString::CMyString(const CMyString &str)
{
m_pData = new char [strlen(str.m_pData) + 1];//注意字符串内存大小需要包括字符串结束符
strcpy(m_pData, str.m_pData);//char *strcpy( char *strDestination, const char *strSource );
}
CMyString::~CMyString()
{
delete[] m_pData;
}
//一般赋值操作符实现
/*
CMyString& CMyString::operator =(const CMyString &str)
{
if(this == &str) //如果是自身赋值,返回自身
return *this;
delete[] m_pData; //否则应该先释放内存,再赋值
m_pData = NULL;
m_pData = new char[strlen(str.m_pData)+1];
strcpy(m_pData,str.m_pData);//赋值
return *this;
}
*/
//考虑异常安全赋值操作符实现
CMyString& CMyString::operator =(const CMyString &str)
{
if(this != &str) //考虑自身赋值
{
CMyString strTemp(str); //创建临时对象,在赋值操作符调用完后会自动释放内存
char* pTemp = strTemp.m_pData;
strTemp.m_pData = m_pData; //依靠临时对象,自动调用析构函数释放实例的内存
m_pData = pTemp; //实现赋值
}
return *this;
}
//用来测试时输出字符串
void myStrPrint(const CMyString& str){
printf("%s",str.m_pData);
}
//单元测试测试函数
//普通赋值
void test1()
{
printf("test1: \n");
printf("The expected result is:\n");
CMyString str1("Hello World!");
myStrPrint(str1);
printf("\n");
CMyString str2;
str2 = str1;
printf("The actuall result is:\n");
myStrPrint(str2);
printf("\n");
}
//自身赋值
void test2()
{
printf("test2: \n");
CMyString str1("Hello World!");
printf("The expected result is:\n");
myStrPrint(str1);
printf("\n");
str1 = str1;
printf("The actuall result is:\n");
myStrPrint(str1);
printf("\n");
}
//连续赋值
void test3()
{
printf("test2: \n");
CMyString str1("Hello World!");
printf("The expected result is:\n");
myStrPrint(str1);
printf("\n");
CMyString str2,str3;
str3 = str2 = str1;
printf("The expected result is:\n");
myStrPrint(str2);
printf("\n");
printf("The expected result is:\n");
myStrPrint(str3);
printf("\n");
}
//测试
int main()
{
test1();
test2();
test3();
return 0;
}
/*
当定义赋值运算符函数时,需要关注一下几点:
1.是否把返回值声明为该类型的引用,并在函数结束前返回实例自身的引用(即*this)。
只有返回一个引用,才可以实现连续赋值
2.是否把传入的参数类型声明为常量引用。可避免调用复制构造函数带来的损耗,提高效率。
3.是否释放自身已有的内存。如果忘记在分配新内存之前释放自身已用的内存,会内存泄露。
4.是否判断传入的参数和当前的实例(*this)是不是同一个实例。如果是同一个,直接返回。
考虑异常安全:
不考虑异常安全的赋值符函数,如果在分配内存时,内存不够,p_Data将是一个空指针,不再
保持有效的状态,容易导致程序崩溃,这不符合异常安全原则。解决办法是在分配内容成功后,
在释放原有内存。还有一个办法是先创建一个临时实例,再交换临时实例和原来的实例,临时
实例内分配失败,原来实例保持不变,仍然是有效状态;若成功,原来实例的原有内存会依靠
临时实例作用结束时自动调用析构函数而释放内存。
*/
==参考剑指offer面试题1
==转载请注明出处