前言:
String类的实现是C++学习者很基本的能力考察,今天自己也来尝试C++风格字符串操作String类的实现:
/*
* to be improved by my own strcpy, strlen, strcmp
* 实现说明: 实现说明:字符串类String的简单实现,内部采用字符数组实现
* 经验说明:经验说明:拷贝构造函数、重载赋值运算符、实现析构函数三个操作在实现自定义类时往往同时出现。
* 参考资料: http://rsljdkt.iteye.com/blog/774188 , 《剑指offer》
*/
#include<iostream>
#include<cstring>
#include<cassert>
#include<cstdlib> // exit()
using namespace std;
class String
{
public:
String(const char *pstr = NULL);
String(const String& other);
~String();
String& operator=(const String& other);
String operator+(const String& other);
int size();
String subStr(int start, int end);
bool operator==(const String& other);
friend ostream& operator<<(ostream& out, const String& other);
private:
char *m_data;
};
String::String(const char *pstr) // 主要在定义是不要加上形参默认值
{
if(pstr == NULL)
{
m_data = new char[1];
if(m_data == NULL)
exit(-1);
*m_data = '\0';
}
else
{
int len = strlen(pstr);
m_data = new char[len+1];
if(m_data == NULL)
exit(-1);
strcpy(m_data, pstr);
}
}
String::String(const String& other)
{
int len = strlen(other.m_data);
m_data = new char[len+1];
if(m_data ==NULL)
exit(-1);
strcpy(m_data, other.m_data);
}
String::~String()
{
if(NULL != m_data)
{
delete m_data;
m_data = NULL;
}
}
/*
在类的成员函数中,返回引用的类对象,当然不能是函数内定义的类对象(会释放掉),一般为this指向的对象;
引用返回左值(即a=b=c是可以的),对于返回值的函数,其返回的是一个右值不可以改变的,
因此返回的是值类型的话不可以连续赋值;
*/
String& String::operator=(const String& other)
{
if(m_data != other.m_data)
{
String strTemp(other);
char *pWant = strTemp.m_data;
strTemp.m_data = m_data;
m_data = pWant;
}
return *this;
}
// "+"运算符的重载不能返回引用,因为它返回的是在函数内定义的类对象;
String String::operator+(const String& other)
{
String ret;
delete[] ret.m_data; // 这就是前面为什么new char[1];的原因,同一delete[]来释放即可
ret.m_data = new char[(strlen(m_data) + strlen(other.m_data) + 1)];
if(m_data == NULL)
exit(-1);
strcpy(ret.m_data, m_data);
strcpy(ret.m_data+strlen(m_data), other.m_data);
return ret;
}
int String::size()
{
return strlen(m_data);
}
String String::subStr(int start, int end)
{
assert(start>=0 && end>=0);
String ret;
if(end > start)
{
delete[] ret.m_data;
ret.m_data = new char[end - start+1];
if(ret.m_data == NULL)
exit(-1);
for(int i=0; i+start < end; i++)
{
ret.m_data[i] = m_data[start+i];
}
ret.m_data[end-start] = '\0';
}
return ret;
}
bool String::operator==(const String& other)
{
return strcmp(m_data, other.m_data) == 0;
}
ostream& operator<<(ostream& out, const String& other)
{
out << other.m_data;
return out;
}
void test()
{
String s = "abcd";
String t = "abcd";
cout << s << (s==t ?" == ":" != ") << t << endl;
String s2 = "Hello";
String s3 = "China";
cout << s2 + s3 << endl;
cout << (s2+s3).subStr(0, s2.size() + s3.size()) << endl;
cout << (s2+s3).subStr(4, 5) << endl;
String s4;
String s5;
s4 = s5 = s2 = s;
cout << "s4= " << s4 << endl;
cout << "s5= " << s5 << endl;
cout << "s2= " << s2 << endl;
}
int main()
{
String s1 = "hello test";
String s2 = s1; // 隐式调用拷贝构造函数
String s3 = "hello test";
String s4("stringDemo"); // 显式调用拷贝构造函数
String s5(s4);
String s6;
String s7 =s6;
cout << "s1= " << s1 << endl;
cout << "s2= " << s2 << endl;
cout << "s4= " << s4 << " s5= " << s5 << endl;
cout << "s6= " << s6 << endl;
cout << "s7= " << s7 << endl;
cout << (s1 == s3) << endl;
cout << "------------------------------\n";
test();
cout << "------------------------------" << endl;
return 0;
}
思考:
1)String是不能被继承的,这里如果要改善可以考虑从这方面入手改进;
2)考虑为什么上面申请一个空间的时候不是new char, 而是new char[1];
3)考虑什么时候返回引用,什么时候返回对象而不是引用;
4)理解为什么参数中可以使用对象的私有成员,感受什么叫做私有成员内部可以被调用,外部不可以被调用;
注:本文代码已在g++环境测试通过, 并通过上面测试用例;
待改进的地方: 不要使用库函数实现String即实现自己my_strlen(), my_strcmp(), 后续博文继续改造;
如果对文章中的内容有疑问或文章出错欢迎讨论指正,相互进步,谢谢;
参考资料:
http://rsljdkt.iteye.com/blog/774188 ,
《剑指offer》