面向对象的编程,首先得设计出良好的类体结构和接口,然后是合理的实现.
如何自己设计并实现一个字符串类?这个问题看似简单,其实里面也有不少的玄机.
1 class CMyString
2 {
3 public:
4 CMyString(char* pStr = NULL);
5 CMyString(const CMyString& rhs);
6 CMyString& operator=(const CMyString& rhs);
7 ~CMyString();
8 .....
9 private:
10 char* pData;
11 int len; //当前字符串长度,不包括'\0'
12 };
CMyString类中包含指向动态分配内存的指针,因而需要自定义copying函数.
CMyString类中字符串长度表示当前字符串长度,不包括'\0',在构造字符串时,保证字符串以'\0'结尾.
1 CMyString::CMyString(char *pStr = NULL)
2 {
3 if(pStr == NULL)
4 {
5 pData = NULL;
6 len = 0;
7 }
8 else
9 {
10 len = strlen(pStr);
11 pData = (char*)malloc(sizeof(char) * (len + 1));
12 memset(pData,'/0',sizeof(char) * (len + 1));
13 strcpy(pData,pStr);
14 }
15 }
16
17 CMyString::~CMyString()
18 {
19 if(pData != NULL)
20 {
21 free(pData);
22 pData = NULL;
23 len = 0;
24 }
25 }
以C语言函数为基础完成构造函数与析构函数.
copying函数的实现如下:
1 CMyString::CMyString(const CMyString &rhs)
2 {
3 memcpy(this,&rhs,sizeof(CMyString);
4 }
5
6 CMyString& CMyString::operator=(const CMyString &rhs)
7 {
8 CMyString *pStr;
9 pStr = new CMyString(rhs); //调用copy constructor
10 return *pStr;
11 }
上述代码实现存在以下几个问题:
1.copy constructor实现过程,参用的是浅拷贝方式,新建的CMyString对象中的pData指针和rhs对象中的pData指针指向同一块内存区域.
2.operator=实现过程,是调用copy constructor创建一个新对象,并返回,将会丢失当前this指针所对应的对象,与operator=的含义不符.
operator=是对已经存在的对象进行赋值,而不是重新创建一个对象.
正如<
针对上述不合理的代码,进行修正,得到如下的代码:
1 CMyString::CMyString(const CMyString& rhs)
2 {
3 if(rhs.pData == NULL)
4 {
5 pData = NULL;
6 len = 0;
7 }
8 else
9 {
10 pData = (char*)malloc(sizeof(char) * (rhs.len + 1));
11 memset(pData,'/0',sizeof(char) * (rhs.len + 1));
12 len = rhs.len; //通过对象访问私有成员变量
13 strcpy(pData,rhs.pData);
14 }
15 }
16 CMyString& CMyString::operator=(const CMyString& rhs)
17 {
18 if(this = &rhs) //证同测试
19 return *this;
20 if(pData != NULL) //*this不是空字符串
21 {
22 free(pData); //释放实例自身已有内存
23 }
24 pData = (char*)malloc(sizeof(char) * (rhs.len + 1));
25 memset(pData,'/0',sizeof(char) * (rhs.len + 1));
26 len = rhs.len; //通过对象访问私有成员变量
27 strcpy(pData,rhs.pData);
28 }
经过修正后,解决了浅拷贝和当前this所指向对象丢失的问题,但这个实现仍不是异常安全的.
在operator=中,如果第24行分配内存失败,产生异常.此时当前的pData所指向内存已被释放,导致pData指向空指针.
此外,第12行代码中,为什么可以通过对象访问私有成员变量,其详细解释请参考:
http://www.cnblogs.com/dwdxdy/archive/2012/07/17/2595741.html
上述解决方法时,可以利用临时指针保存当前的pData,然后当完成赋值操作后,再根据临时指针释放原始pData所指的空间.
1 CMyString& CMyString::operator=(const CMyString& rhs)
2 {
3 char* pOri = pData; //保存原始指针
4 pData = (char*)malloc(sizeof(char) * (rhs.len + 1));
5 memset(pData,'/0',sizeof(char) * (rhs.len + 1));
6 len = rhs.len;
7 strcpy(pData,rhs.pData);
8 free(pOri); //释放原始指针所指内存
9 return *this;
10 }
这种实现,当前rhs和*this是同一个对象,也可以安全完成赋值操作.
参考资料:
Effective C++
http://www.cnblogs.com/xwdreamer/archive/2012/05/14/2500632.html
http://blog.csdn.net/zijinshi/article/details/111039
http://www.cnblogs.com/dwdxdy/archive/2012/07/17/2595821.html
原文链接: https://www.cnblogs.com/dwdxdy/archive/2012/07/21/2602303.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/56173
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!