C++学习笔记------Mstring类的实现
作者:互联网
2.2 Mstring类的实现
Mstring类基本结构:
- push_back(), pop_back()
- is_full(), is_empty()
- 扩容revert()
- 输出运算符重载、等号赋值运算符重载、[]运算符重载、比较运算符重载、加法(拼接)运算符重载等
class Mstring
{
private:
char* _str;
int _len;//容量
int _val_len;//数据长度(有效数据长度),不包括'\0'
/*
以下成员方法不对外提供
*/
bool is_full();//判满
bool is_empty();//判空
void revert();//按照1.5倍进行扩容
public:
Mstring();
Mstring(const char* str);
Mstring(const Mstring& src);
Mstring& operator=(/*this,*/const Mstring& src);
//增加和删除字符
void push_back(char c);
char pop_back();
bool operator>(/*this, */const Mstring& src);
bool operator==(const Mstring& src);
Mstring operator+(/*this, */const Mstring& src);
//->(箭头运算符), * 解引用运算符
//普通对象调用该方法
char& operator[](int pos);//普通对象可以进行修改
//常对象调用该方法
char operator[](/*常对象指针*/int pos)const; //对常对象无法进行修改
~Mstring()
{//防止内存泄露
if (_str != NULL)
{
delete[]_str;
}
/*_str = NULL; 不用加吗?*/
}
friend ostream& operator<<(ostream& out, const Mstring& src);
};
- 不对外部提供的成员方法的实现
实际上该部分并非要一开始实现,在完成push_back()和pop_back()时可以先使用,后面再考虑实现
bool is_full()//判满
{//_len表示实际容量,_val_len表示有效字符(不包括'\0')
return _len == _val_len+1;
}
bool is_empty()
{
return _val_len == 0;//判断有效字符个数是否为0
}
void revert()//按照1.5倍进行扩容
{
if (_len==0)//调用默认构造函数时,_len是0,这时候接一个push_back()操作,就需要扩容
{
_len = 10;//默认字符容量从10开始
}
_len = _len + (_len >> 1);//右移除2,执行效率高
char* tmp = new char[_len];//开辟一块新的内存
strcpy_s(tmp, _val_len+1, _str);//把已有内容进行拷贝,包括'\0'
//释放原来的内存,防止内存泄漏
if (_str != NULL)
{
delete[]_str;
}
_str = tmp;
}
- 构造函数实现
Mstring()//在类构造之前一定要先构造它的所有成员
//:_str(),_len(),_val_len(),成员属性的定义,一定会有成员属性的定义或者初始化,只是大部分都是系统自动完成了
//const,引用以及成员对象(可能)需要手动实现
{
_str = NULL;
_len = 0;
_val_len = 0;
}
Mstring(const char* str)
{
if (str == NULL)
{
_str = NULL;
_len = 0;
_val_len = 0;
}
_len = strlen(str) + 1;//+1表示'\0'
_val_len = _len-1;
_str = new char[_len];
strcpy_s(_str, _len, str);
}
Mstring(const Mstring& src)//拷贝构造
{
_len = src._len;
_val_len = src._val_len;
//防止浅拷贝,拷贝构造哪来的释放
_str = new char[_len];
strcpy_s(_str, _len, src._str);
}
- push_back()和pop_back()的实现
void push_back(char c)
{
if (_str==NULL)//默认构造后,直接push_back()
{
_val_len = 1;//也就是实际容量从2开始才行
}
if (is_full())
{
revert();
}
if (_val_len == 0)
{
_val_len = 1;
}
_str[_val_len] = c;//把原来'\0'的位置覆盖掉
_str[++_val_len] = 0;//后一位放'\0',_val_len加一
}
char pop_back()
{
if (is_empty()||_str==NULL)
{
return 0;
}
char c = _str[_val_len - 1];
_str[_val_len] = 0;
_val_len--;
return c;//不能返回局部变量的引用和指针
}
- 等号赋值运算符重载实现
Mstring& operator=(/*this,*/const Mstring& src)
{
//防止自赋值,避免下一步释放内存时出错
if (&src != this)
{
return *this;
}
//防止内存泄漏
if (_str != NULL)
{
delete[]_str;
}
//防止浅拷贝
_len = src._len;
_val_len = src._val_len;
_str = new char[_len];
strcpy_s(_str, _len, src._str);
return *this;
}
- ==, >, +运算符重载实现
bool operator>(/*this, */const Mstring& src)
{//strcmp(str1, str2)--->相等返回0, str1>str2返回>0, str1>str2返回<0
return strcmp(_str, src._str)>0;
}
bool operator==(const Mstring& src)
{
return strcmp(_str, src._str) == 0;
}
//所谓加法,在这时拼接操作
Mstring operator+(/*this, */const Mstring& src)
{
Mstring tmp = *this;
//注意i=0, src._str[0]是第一个元素的位置,src._str[_val_len-2]是'\0'的位置
for (int i=0;i<src._val_len-1;i++) //(_val_len-1)---->'\0'的位置
{
tmp.push_back(src._str[i]);//push_back()有扩容处理
}
return tmp;
}
- [ ] 运算符重载实现
char& operator[](int pos)//普通对象可以进行修改
{
return _str[pos];
}
//常对象调用该方法
char operator[](/*常对象指针*/int pos)const //对常对象无法进行修改
{
return _str[pos];
}
- 输出运算符重载实现
//注意在类中设置友元
ostream& operator<<(ostream& out, const Mstring& src)
{
for (int i=0;i<src._val_len;i++)
{
out << src._str[i];
}
return out;
}
测试:
int main()
{
Mstring str("12345");
cout << str<<endl;
for (int i = '0'; i < '9'; i++)
{
str.push_back(i);
cout << str << endl;
}
for (int i = 1; i < 9; i++)
{
cout << str.pop_back() << endl;
cout << str << endl;
}
return 0;
}
输出结果:
标签:Mstring,val,src,len,char,C++,str,------ 来源: https://www.cnblogs.com/ChenFei-Blogs/p/15095423.html