作为一只小白,编程能力差到爆炸,故决定从现在开始拜读《剑指offer》,此为一刷笔记。说实话,我觉着我这种垃圾水平,至少得多刷几次才能有一丢丢进步,究竟能刷多少遍还请拭目以待。
好的,其实虽然很不好意思,但是我看到赋值运算符的时候愣了一会儿,后来才反应过来就是“=”。
接着看了一下声明,完球了,两年前学的C++忘光光了,脑子里都是问题:
为啥要const类型?“~”是啥意思??
啊啊啊啊啊,为啥要这样声明啊啊啊啊????
罪恶啊罪恶,对不起C++老师!
认真思考了一下,结合书上给出的四个点,渐渐懂了一些。
首先,第一个点,返回类型得是类引用,不能是void,对应一下第三条~Cmystring(void),如果是void就调用了析构函数,就是扫尾清理,释放内存空间。
再看第二个点,传入的要是类引用,而且状态不会发生改变,所以引用参数加上const关键字,对应第二条。
接着第三个点和第四个点,是否释放内存,这个需要我们实现。
继续往下看,看到适用于初级程序员的解法,对应一下四个点来看看~~
实在不好意思,看了几遍才看懂,把博主自己的理解写在了下面,看来路还很长。。。
//满足返回值类型声明为该类类型的引用
//在C++中“::”为域操作符,即定义了一个在CMyString类里的成员函数
//“operator=”为等号重载标志,相当于一个函数
//(const CMyString &str)表示该成员函数的参数为类类型的引用
CMyString& CMyString::operator =(const CMyString &str)
{
//对应第四点,判断传入的参数是否与当前的实例(*this)相同,如果相同,直接返回
if(this== &str)
return *this;
//释放实例m_pData的内存,突然有点迷,m_pData是啥子???接着往下看。
delete []m_pData;
m_pData=NULL;
//给m_pData分配内存,分配多少呢?就和传入参数str中的m_pData大小一样。到这里就懂了m_pData的含义。就是该类的”值“,赋值的”值“。注意,这里埋下了安全的隐患!!
m_pData=new char[strlen(str.m_pData)+1];
//验证上面猜想的正确性,strcpy复制了~~
strcpy(m_pData,str.m_pData);
return *this;//返回值类型为类类型的引用。
}
继续往下,看到作为一名高级程序员的解法,要考虑异常安全性。
emmmm,看到这里,不由得想问,异常安全性是个啥?
不由自主联想到了java里的try、throw and catch,哈哈哈哈
正常的解释来了!!
异常安全的代码,满足两个条件:
1、异常中立性:当代码引发异常时,这个异常能够保持原样传递到外层调用代码
2、异常安全性:抛出异常后,资源不泄露,数据不恶化(eg:正常指针变野指针,所谓的野指针就是指针在首次使用之前没有初始化)
3、少try catch,会很丑。。。
实现异常安全性的方法:
1、先用new分配新内容再用delete释放已有的内容,但存在局限性,即只在分配内容成功之后再释放原来的内容,但是当内存分配失败时,CMyString的实例不会被修改。
2、先创建一个临时实例,再交换临时实例和原来的实例,如下代码
CMyString& CMyString::operator=(const CMyString &str)
{
if(this!=&str)
{
//创建临时实例strTemp
CMyString strTemp(str);
//将临时实例的m_pData赋值给变量pTemp
char* pTemp=strTemp.m_pData;
//把pTemp与实例自身的m_pData进行交换
m_pData=pTemp;
}
//由于strTemp为局部变量,现在已经出了作用域,自动调用析构函数,释放临时变量strTemp.m_pData的内存
return *this;
}
下面给出完整解题代码!!!
#include <iostream>
#include <cstdlib>
#include <cstring>
using namespace std;
class CMyString
{
public:
//构造函数
CMyString(char* pData=NULL);
CMyString(const CMyString& str);
//析构函数
~CMyString(void);
//运算符重载
CMyString& operator=(const CMyString& str);
//输出函数
void print();
private:
char* m_pData;
};
CMyString::CMyString(char* pData)
{
if(pData==NULL)
{
m_pData=new char[1];
m_pData[0]='\0';
}
else
{
int length=strlen(pData);
m_pData=new char[length+1];
strcpy(m_pData,pData);
}
}
CMyString::CMyString(const CMyString &str)
{
int length=strlen(str.m_pData);
m_pData=new char[length+1];
strcpy(m_pData,str.m_pData);
}
CMyString::~CMyString()
{
delete[] m_pData;
}
CMyString& CMyString::operator=(const CMyString& str)
{
if(this==&str)
return *this;
delete[] m_pData;
m_pData=new char[strlen(str.m_pData)+1];
strcpy(m_pData,str.m_pData);
return *this;
}
void CMyString::print()
{
cout<<m_pData<<endl;
}
//一般情况下的测试
void Test_1()
{
cout<<"Test1 begins:"<<endl;
char* text="hello world!";
CMyString str1(text);
CMyString str2;
str2=str1;
cout<<"Expected result: "<<text<<endl;
cout<<"Actual result: ";
str2.print();
}
//自己给自己赋值的测试
void Test_2()
{
cout<<"Test2 begins:"<<endl;
char* text="hello world!";
CMyString str1(text);
str1=str1;
cout<<"Expected result: "<<text<<endl;
cout<<"Actual result: ";
str1.print();
}
//连续赋值的测试
void Test_3()
{
cout<<"Test3 begins:"<<endl;
char* text="hello world!";
CMyString str1(text);
CMyString str2,str3;
str3=str2=str1;
cout<<"Expected result: "<<text<<endl;
cout<<"Actual result: ";
str2.print();
cout<<"Expected result: "<<text<<endl;
cout<<"Actual result: ";
str3.print();
}
int main()
{
Test_1();
cout<<"############################"<<endl;
Test_2();
cout<<"############################"<<endl;
Test_3();
}
贴出在codeblocks 17.0下的测试结果: