详解C++中实现继承string类的MyString类的步骤

 更新时间:2020年4月25日 17:35  点击:2150

昨天师兄又出了道测试题,让我们实现类似于string类的没有MyString类,刚开始很头疼,可是真正在自己写代码的时候又很兴奋的发现,这个过程真的是个很宝贵的机会,让我又有机会可以很好的熟悉回顾C++的很多知识—类设计,构造析构函数,成员函数,友元函数,引用,重载,字符串操作,动态内存分布。。。。。于是昨天花了半天时间写了300多行代码,并认真的进行了相关测试、修改和总结。因为内容有点丰富,所以想分几次写出来,条理也清楚些。

类的空间分配:类给它的每个对象都分配了独立的空间去存储它的数据成员,所有的对象公共的访问类方法进行操作。同时在对象的独立空间中,不包括数据成员动态分配的空间,对象只是记录了动态分配空间的地址(所以在析构函数调用的时候只是删除了对像空间,同时需要用new来删除动态分配的地址)。

一、类声明—mystring.h:
1. 构造函数:
专门用于构建新对象,给成员数据分配必要的内存空间并将值赋给新对象的成员数据。
默认构造函数:
在未提供显式初始化值时,被用来创建对象的构造函数(所以它一般没有参数)

MyString();

复制构造函数:
用于将一个对象复制到新创建的对象中(当然这个被复制的对象必须已经存在)。

MyString(const MyString &str);

给定了一定初始化参数的构造函数:
参数列表中的值会一次赋给新创建对象的各个成员函数:

MyString(const char*str);

2.析构函数:
当对象过期时删除对象所占的内存空间,并且当对象创建时有用New请求的内存空时,在析构函数中同时要调用delete对原来分配的 内存空间进行释放,以防止内存泄露。
~MyString();

3.成员函数:
重载赋值成员函数:

MyString &operator=(const MyString &str);    //利用已有的string对象通过=给一个对象进行赋值
MyString &operator=(const char*str);       //直接用常量字符串进行赋值

一般赋值函数:

MyString &assign(const MyString&str);
MyString &assign(const char*sstr);

几个处理字符串的成员函数:

size_t getsize()const;                  //返回字符串大小
void clear();                      //把字符串清空
bool empty();                       //判断字符串是否为空
void swap(MyString &str);              //交换两个字符串
int compare(const MyString &str)const;      //比较2个字符串的大小
//第一个const说明显式调用的字符串不可更改,括号外面的const说明隐式调用的字符串不可更改,只读数据    
int compare(const char*str);           

追加函数:

MyString &operator+=(const MyString&str);
MyString &operator+=(const char*str);
MyString &append(const MyString&str);
MyString &append(const char *str);

生成字串:

MyString substr(size_t pos = 0,n=npos) const; 
生成字串,从第0个位置开始长度为n,若N超过长度,则为输出整个字符串的长度

4.友元函数(运算符重载):
友元函数一般都是在类得声明中进行定义,它不属于类得成员函数,但是它和类得成员函数一样同样的可以对类得所有数据成员进行访问。

friend bool operator==(const MyString &str1,const MyString &str2);
friend bool operator==(const char *str,const MyString &str2);
friend bool operator==(const MyString &str1,const MyString *str2);
friend bool operator>(const MyString &str1,const MyString &str2);
friend bool operator>(const char*str1,const MyString &str2);
friend bool operator>(const MyString &str1,const char*str2);

同样还有<等各种比较。

friend MyString operator+(const MyString &str1,const MyString &str2);
friend MyString operator+(const char*str1,const MyString &str2);      //两个字符串进行相加
friend MyString operator+(const MyString &str1,const char*str2);

friend ostream & operator<<(ostream &os,const MyString &str);       //输出命令符的重载

5.成员数据变量:

char *string;                     //指向字符串的指针
int length;                       //字符串的长度
static const int string_number = 0;      //计数创建的字符串的数目

二、实现.cpp文件:
1.构造函数和析构函数:

MyString::MyString() 
{ 
  length = 0; 
  string = new char; 
  char *s = "/0"; 
  memcpy(string,s,1); 
  ++string_number; 
} 
 
MyString::MyString(const char*str) 
{ 
  length = strlen(str); 
  string = new char(length+1); 
  memcpy(string,s,length); 
  ++string_number; 
} 
MyString::MyString(MyString &str) 
{ 
  length = str.length; 
  string = str.string; 
  ++string_number; 
} 
 
MyString::~MyString() 
{   
  delete[]string; 
  --string_number; 
} 

几个注意的问题:
1)构造函数中必须给所有的数据成员进行初始化。
2)注意在给指向字符串的指针赋值时,左右类型的对应。
char *s代表一个指向字符串的指针,所有右边必须是一个字符串常量“/0”,而不能是‘/0'.
3)一个指针只能指向一个地址,不能同时指向两个。
在给string分配了地址之后,下一步我们肯定是确定分配的地址中存放的具体内容,那么这个时候我们都是使用strcpy()或者是
memcpy()把对应的字符串存入地址中。
如果原来我们成这样实现:

   MyString::MyString()
  {
    length = 0;
    string = new char;
    string = "/0";
    ++string_number;
  }

那么我们在编译和实现的时候都不会发现有什么错,但是析构函数使用delete【】释放内存使执行结果会出现乱码,因为string=“/0”
让它指向了一个字符串,并没有分配内存空间,所以在释放的时候就会出现错误。
4)析构函数中的重要语句 delete【】不要忘
析构函数在使用的时候只会释放为对象分配的空间,但是对象的空间中只是存储了数据成员分配内存的地址,所以并没有释放数据成员
的内存空间,必须使用delete[]来进行释放,防止内存泄露 
2.重载运算符的成员函数:

MyString &MyString::operator+=(const MyString&str) 
{ 
   char *dest; 
   dest = new char[str.length+length+1]; 
   memcpy(dest,string,length); 
   memcpy(dest+length,str.string,str.length+1); 
   delete[]string; 
   length = length+str.length; 
   string = dest; 
   return*this; 
} 
MyString &MyString::operator+=(const char*str) 
{ 
   char *dest; 
   dest = new char[strlen(str)+length+1]; 
   memcpy(dest,string,length); 
   memcpy(dest+length,str,strlen(str)+1); 
   delete[]string; 
   string = dest; 
   return *this; 
} 
 
 //字符串赋值 
MyString &MyString::operator=(const MyString&str) 
{ 
  if(&str == this) 
    return *this; 
  delete[]string; 
  string = new char[str.length]; 
  memcpy(string,str.string,str.length); 
  length = str.length; 
  return *this; 
} 

 
注意的幾個問題:
1)+=运算中,调用函数的对象最终字符串长度肯定大于其原来的长度,所以在这个函数调用过程中,我们必须给字符串重新分配一块
两个字符串长度和大小的内存区域。但是因为函数返回值又必须是原调用对象的引用,所以我们要定义一个中间变量指针来存储2个
字符串合并结果,最后释放string指针原来的内存区域后,再让它指向合并字符串。
2)“=”赋值运算肯定和构造函数的初始化不一样。
在使用这个方法以前,那么对象肯定至少已经通过调用构造函数数据成员有了一定的值。所以这个时候我们首先判断两个对象是否
相等。相等的话返回原对象,如果不等:
那么两个对象的字符串长度肯定不同。所以我们先释放原字符串内存空间,然后根据赋值对象的字符串长度分配内存空间并把字符
串内存拷贝过去。
3.字符串处理的几个函数:

size_t MyString::getsize(MyString &str) 
{ 
 return strlen(str.string); 
} 
void MyString::clear() 
{ 
 length = 0; 
 while(string!='/0') 
 *string ='/0'; 
} 
bool MyString::empty() 
{ 
 return strlen(string)==0; 
} 
int MyString ::compare(const MyString &str) 
{ 
  return compare(string,str.string); 
} 
void MyString::swap(MyString &str) 
{ 
  char *temp; 
  temp = string; 
  string = str.string; 
  str = temp; 
} 
Mystring MyString::substr(sizez_t pos=0,size_t n )const 
{ 
  MyString string; 
  delete[]string.string; 
  if(n>length) 
  { 
   string.length = length; 
   string.string = new char[length+1]; 
   memcpy(string.string,string,length+1); 
    return string; 
  } 
  length = n; 
  string.string = new char[length+1]; 
  memcpy(string.string,string,length+1); 
  return string; 
} 

注意的几个问题:
1)在这几个函数的实现中,我们可以直接调用c语言中几个对字符串处理的<string.h>函数进行实现
2)clear()函数中注意,只是把每个内存区域的字符置为0,并不能通过delete[]来释放内存空间,这样很容易和析构函数一起造成
两次释放内存空间引起错误。
3)swap()实现交换的这个函数中,我们可以直接定义中间变量指针实现,不用重新分配内存空间全部进行转存,这个对于析构函数
的析构没有影响。
4.友元函数:

friend bool operator==(const MyString &str1,const MyString &str2) 
 
  return strcmp(str1.string,str2.string)==0; 
 
friend MyString operator+(const MyString &str1,const MyString &str2) 
{ 
  MyString mystring; 
  char *dest; 
  dest = new char[str1.length+str2.length+1]; 
  memcpy(dest,str1.string,str1.length); 
  memcpy(dest+str1.length,str2.string,str2.length+1); 
  delete[]mystring.string; 
  mystring.string = dest; 
  mystring.length = str1.length+str2.length; 
  return mystring; 
} 
friend ostream &operator<<(ostream &os,const MyString &str) 
{ 
  os<<str.string; 
  return os; 
} 

注意的问题和上面差不多,这里就不重复了~~~
其他几个函数实现都基本雷同~

[!--infotagslink--]

相关文章

  • C++ STL标准库std::vector的使用详解

    vector是表示可以改变大小的数组的序列容器,本文主要介绍了C++STL标准库std::vector的使用详解,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2022-03-06
  • C++中取余运算的实现

    这篇文章主要介绍了C++中取余运算的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-23
  • 详解C++ string常用截取字符串方法

    这篇文章主要介绍了C++ string常用截取字符串方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
  • C++调用C#的DLL程序实现方法

    本文通过例子,讲述了C++调用C#的DLL程序的方法,作出了以下总结,下面就让我们一起来学习吧。...2020-06-25
  • C++中四种加密算法之AES源代码

    本篇文章主要介绍了C++中四种加密算法之AES源代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。...2020-04-25
  • mybatis 返回Integer,Double,String等类型的数据操作

    这篇文章主要介绍了mybatis 返回Integer,Double,String等类型的数据操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-11-25
  • C++ 整数拆分方法详解

    整数拆分,指把一个整数分解成若干个整数的和。本文重点给大家介绍C++ 整数拆分方法详解,非常不错,感兴趣的朋友一起学习吧...2020-04-25
  • C++中 Sort函数详细解析

    这篇文章主要介绍了C++中Sort函数详细解析,sort函数是algorithm库下的一个函数,sort函数是不稳定的,即大小相同的元素在排序后相对顺序可能发生改变...2022-08-18
  • C++万能库头文件在vs中的安装步骤(图文)

    这篇文章主要介绍了C++万能库头文件在vs中的安装步骤(图文),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-23
  • 详解C++ bitset用法

    这篇文章主要介绍了C++ bitset用法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
  • 浅谈C++中的string 类型占几个字节

    本篇文章小编并不是为大家讲解string类型的用法,而是讲解我个人比较好奇的问题,就是string 类型占几个字节...2020-04-25
  • C++ Eigen库计算矩阵特征值及特征向量

    这篇文章主要为大家详细介绍了C++ Eigen库计算矩阵特征值及特征向量,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-04-25
  • 【C#基础】Substring截取字符串的方法小结(推荐)

    这篇文章主要介绍了Substring截取字符串方法小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-06-25
  • java中String类型变量的赋值问题介绍

    下面小编就为大家带来一篇java中String类型变量的赋值问题介绍。小编觉得挺不错的。现在分享给大家,给大家一个参考。...2016-03-28
  • C++ pair的用法实例详解

    这篇文章主要介绍了C++ pair的用法实例详解的相关资料,需要的朋友可以参考下...2020-04-25
  • VSCode C++多文件编译的简单使用方法

    这篇文章主要介绍了VSCode C++多文件编译的简单使用方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-03-29
  • C++中的循环引用

    虽然C++11引入了智能指针的,但是开发人员在与内存的斗争问题上并没有解放,如果我门实用不当仍然有内存泄漏问题,其中智能指针的循环引用缺陷是最大的问题。下面通过实例代码给大家介绍c++中的循环引用,一起看看吧...2020-04-25
  • C++随机点名生成器实例代码(老师们的福音!)

    这篇文章主要给大家介绍了关于C++随机点名生成器的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
  • C++如何删除map容器中指定值的元素详解

    map容器是C++ STL中的重要一员,删除map容器中value为指定元素的问题是我们经常与遇到的一个问题,下面这篇文章主要给大家介绍了关于利用C++如何删除map容器中指定值的元素的相关资料,需要的朋友可以参考借鉴,下面来一起看看吧。...2020-04-25
  • C++ 约瑟夫环问题案例详解

    这篇文章主要介绍了C++ 约瑟夫环问题案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下...2021-08-15