C++中sting类的简单实现方法

 更新时间:2016年08月22日 09:23:12   作者:chentingting的小天地  
这篇文章主要介绍了C++中sting类的简单实现方法的相关资料,需要的朋友可以参考下

String

在C++的学习生涯我中发现String类的功能十分强大,所以我们是很有必要模拟实现它的,况且在面试的时候模拟实现一个String类也是面试官经常会考的,但是因为外界因素的限制我们是不可能模拟的和库里的string一致的(C++库里的string功能更强大),所以今天我们只模拟实现string的基本功能-构造函数,拷贝构造函数,析构函数,赋值运算符重载,运算符+=的重载,运算符[]的重载,c_str(得到一个C风格的字符指针,可操作字符串),Size,Push_Back,Insert(深拷贝),以及用写时拷贝copy_on_write的方式实现基本的String类

深拷贝的方式

class String 
{ 
friend ostream &operator<<(ostream &os,String &s); 
public: 
String(const char *str=""); //全缺省的构造函数,解决空字符串的问题 
String(const String &ps); //深拷贝 
String &operator=(String s); 
String &operator+=(const char * s); 
const char *C_Str()const //得到C风格的字符指针 
{ 
return _pstr; 
} 
char &operator[](size_t index) 
{ 
return _pstr[index]; 
} 
size_t Size()const 
{ 
return _size; 
} 
void PushBack(char c); 
String &Insert(size_t pos,const char *str); 
//String &operator=(String &s) 
//{ 
// cout<<"String &operator=(String &s)"<<endl; 
// if(this != &s) 
// { 
// delete[]_pstr; 
// _pstr=new char[strlen(s._pstr)+1]; 
// strcpy(_pstr,s._pstr); 
// } 
// return *this; 
//} 
~String() 
{ 
cout<<"~String()"<<endl; 
if(_pstr != NULL) 
{ 
delete[]_pstr; 
_pstr=NULL; 
_size=0; 
_capacity=0; 
} 
} 
private: 
void CheckCapacity(int count); 
private: 
int _size; 
int _capacity; 
char *_pstr; 
}; 
ostream &operator<<(ostream &os,String &s) 
{ 
os<<s._pstr; 
return os; 
} 
String::String(const char *str) 
:_size(strlen(str)) 
,_capacity(strlen(str)+1) 
,_pstr(new char[_capacity]) 
{ 
cout<<"String()"<<endl; 
strcpy(_pstr,str); 
} 
String::String(const String &ps) 
:_size(ps._size) 
,_capacity(strlen(ps._pstr)+1) 
,_pstr(new char[_capacity]) 
{ 
cout<<"String(const String &ps)"<<endl; 
strcpy(_pstr,ps._pstr); 
} 
String &String::operator=(String s) 
{ 
cout<<"String &operator=(String s)"<<endl; 
std::swap(_pstr,s._pstr); 
std::swap(_size,s._size); 
std::swap(_capacity,s._capacity); 
return *this; 
} 
void String::CheckCapacity(int count) 
{ 
if(_size+count >= _capacity) 
{ 
int _count=(2*_capacity)>(_capacity+count)?(2*_capacity):(_capacity+count); 
char *tmp=new char[_count]; 
strcpy(tmp,_pstr); 
delete[]_pstr; 
_pstr=tmp; 
_capacity=_count; 
} 
} 
void String::PushBack(char c) 
{ 
CheckCapacity(1); 
_pstr[_size++]=c; 
_pstr[_size]='\0'; 
} 
String &String::operator+=(const char * s) 
{ 
CheckCapacity(strlen(s)); 
while(*s) 
{ 
_pstr[_size++]=*s; 
s++; 
} 
_pstr[_size]='\0'; 
return *this; 
} 
String &String::Insert(size_t pos,const char *str) 
{ 
char *tmp=new char[strlen(_pstr+pos)]; 
strcpy(tmp,_pstr+pos); 
CheckCapacity(strlen(str)); 
while(*str) 
{ 
_pstr[pos++]=*str; 
str++; 
} 
strcpy(_pstr+pos,tmp); 
return *this; 
}

通过测试上述代码可正常运行,特别是在实现赋值运算符重载的时候我们使用了两种方式,值得一提的是应用swap函数来实现赋值运算符的重载(在传参时不可以传引用),因为应用swap函数实现是根据临时变量的创建并且该临时变量出作用域就会自动调用析构函数销毁(现代的方法)

测试深拷贝的方法

void text1() 
{ 
String str1("hello"); 
String str2(str1); 
String str3; 
str3=str1; 
cout<<str1<<endl; 
cout<<str2<<endl; 
cout<<str3<<endl; 
cout<<strlen(str1.C_Str())<<endl; //5 
str1[4]='w'; 
cout<<str1<<endl; //hellw 
} 
void text2() 
{ 
String str1("abcd"); 
cout<<str1<<endl; 
str1.PushBack('e'); 
str1.PushBack('f'); 
str1.PushBack('g'); 
str1.PushBack('h'); 
str1.PushBack('i'); 
cout<<str1<<endl; 
cout<<str1.Size()<<endl; 
} 
void text3() 
{ 
String str1("hello"); 
String str2("hello world"); 
String str3(str2); 
str1+=" "; 
str1+="world"; 
cout<<str1<<endl; 
str2.Insert(6," abc "); 
cout<<str2<<endl; 
}

实现了深拷贝的方法那仫有没有更加高效的方法呢?当然,那就是写时拷贝,我们发现在上述深拷贝的版本里实现的拷贝构造函数又为新的对象重新开辟空间(防止浅拷贝的后遗症:浅拷贝是值拷贝使得两个指针指向同一块空间,在析构该空间时对同一块空间释放多次就会出现问题),那仫如果我们继承了浅拷贝的后遗症-就让多个指针指向同一块空间,此时我们只需要设置一个指针变量让它记录指向这块空间的指针个数,在析构时只要该指针变量的内容为1我们就释放这块空间否则就让计数器减1,这就是写时拷贝的主要思想,下面就让我们用写时拷贝的方法实现一个简单的String类吧

写时拷贝的方法

//写时拷贝的方式 
class String 
{ 
friend ostream& operator<<(ostream & os,String &s); 
public: 
String(const char *str="") 
:_str(new char[strlen(str)+1+4]) 
{ 
cout<<"构造"<<endl; 
_str+=4; 
*((int *)(_str-4))=1; 
strcpy(_str,str); 
} 
String(String &s) 
{ 
cout<<"拷贝构造"<<endl; 
++*((int *)(s._str-4)); 
_str=s._str; 
} 
String &operator=(const String &s) 
{ 
cout<<"赋值语句"<<endl; 
if(--*(int *)(_str-4) == 0) 
{ 
delete[](_str-4); 
} 
++(*(int *)(s._str-4)); 
_str=s._str; 
return *this; 
} 
char &operator[](int index) //写时拷贝 
{ 
assert(index >= 0 && index < (int)strlen(_str)); 
if(*(int *)(_str-4) > 1) 
{ 
--*(int *)(_str-4); 
char *tmp=new char[strlen(_str)+5]; 
strcpy(tmp+4,_str); 
delete[](_str-4); 
_str=tmp+4; 
*(int *)(_str-4)=1; 
} 
return _str[index]; 
} 
~String() 
{ 
cout<<"析构"<<endl; 
if(--*(int *)(_str-4) == 0) 
{ 
cout<<"释放"<<endl; 
delete[](_str-4); 
} 
} 
private: 
char *_str; 
}; 
ostream& operator<<(ostream &os,String &s) 
{ 
os<<s._str; 
return os; 
}

在这里我们将指针指向的计数器的位置放置在数据空间的前四个字节处

测试用例:

void test1() 
{ 
String str1("abcd"); 
cout<<str1<<endl; 
String str2(str1); 
cout<<str2<<endl; 
String str3; 
str3=str1; 
cout<<str3<<endl; 
} 
void test2() 
{ 
String str1("abcd"); 
cout<<str1<<endl; 
String str2; 
str2=str1; 
cout<<str2<<endl; 
str2[2]='w'; 
cout<<str2<<endl; 
}

以上所述是小编给大家介绍的C++中sting类的简单实现方法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

相关文章

  • C/C++实现string和int相互转换的常用方法总结

    C/C++实现string和int相互转换的常用方法总结

    在C++编程中,经常需要在字符串(string)和整型(int)之间进行转换,本文将详细介绍几种在C和C++中实现这两种类型转换的常用方法,有需要的可以参考下
    2024-01-01
  • C语言 解压华为固件的实例代码

    C语言 解压华为固件的实例代码

    这是解压华为固件(update.app)的C语言。。其实这也是我翻115翻出来的。。。
    2013-08-08
  • 在C++中把字符串转换为整数的两种简单方法

    在C++中把字符串转换为整数的两种简单方法

    经常会遇到类型转换,本文主要介绍了C++中把字符串转换为整数的两种简单方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-06-06
  • C语言用fun函数实现两个数的交换方式

    C语言用fun函数实现两个数的交换方式

    这篇文章主要介绍了C语言用fun函数实现两个数的交换方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-12-12
  • C语言超详细讲解排序算法下篇

    C语言超详细讲解排序算法下篇

    今天我们主要难点有快速排序和归并排序,会简单涉及到二叉树相关知识,相对来说比较抽象!所以如果有看不懂或者不明白的地方可以看看我之前的详解二叉树
    2022-04-04
  • 简要对比C语言中的dup()函数和dup2()函数

    简要对比C语言中的dup()函数和dup2()函数

    这篇文章主要介绍了简要对比C语言中的dup()函数和dup2()函数,是C语言入门学习中的基础知识,需要的朋友可以参考下
    2015-08-08
  • C++深入分析回顾函数重载

    C++深入分析回顾函数重载

    C++ 允许多个函数拥有相同的名字,只要它们的参数列表不同就可以,这就是函数的重载(Function Overloading),借助重载,一个函数名可以有多种用途
    2022-06-06
  • 解析C++中构造函数的默认参数和构造函数的重载

    解析C++中构造函数的默认参数和构造函数的重载

    这篇文章主要介绍了解析C++中构造函数的默认参数和构造函数的重载,是C++入门学习中的基础知识,需要的朋友可以参考下
    2015-09-09
  • QTableWidget设置只让某一列可编辑的实现

    QTableWidget设置只让某一列可编辑的实现

    本文介绍了如何将QTableWidget的某一列设置为可编辑,以便用户可以输入自定义数据,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-08-08
  • C++编写高性能服务器实例教程

    C++编写高性能服务器实例教程

    这篇文章主要介绍了如何用C++编写高性能服务器,文中通过示例代码介绍的非常详细,对大家学习C++有一定的参考价值,需要的朋友们可以了解下
    2020-06-06

最新评论