/*************************************************************** 题目:如下为类型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
==转载请注明出处
原文:http://blog.csdn.net/walkerkalr/article/details/20155127