通过对string类的实现来熟悉c++库中string都有哪些方法
mstring 基础类
对所有已经确定好在之后是不会改变的函数都定义成为常函数
size back front empty
#ifndef MSTRING_H
#define MSTRING_H
#include<iostream>
using namespace std;
#define DEFAULT_LEN 10
class Mstring
{
public:
Mstring(const char* str = NULL); //带参构造函数
Mstring(const Mstring& src);//拷贝构造函数
Mstring& operator=(const Mstring& src); //等号运算符重载
~Mstring();//析构函数
void push_back(char c); //尾插
void pop_back(); //弹出最后一个元素
char back()const; //返回最后一个元素
char front()const; //返回第一个元素
bool empty()const; //判空
int size()const; //字符串大小
Mstring operator+(const Mstring& str); //加号运算符重载
char& operator[](int pos); //中括号运算符重载
char operator[](int pos)const; //中括号运算符重载 常函数
//写在类外的函数必须要加友元
friend ostream& operator<<(ostream& out, const Mstring& str); //类外实现的输出函数 形参字符串要加上const 不能被修改
friend istream& operator>>(istream& in, Mstring& str); //类外实现的输入函数 输入的字符串一定不是常量
private:
//对外界不提供
bool full()const; //判满
void revert();//扩容
char* _str;
int _len; //当前空间总长度
int _val_len;//已经占用的长度 数据长度
};
#endif // !MSTRING_H
#include"mstring.h"
Mstring::Mstring(const char* str)
{
if (NULL == str)
{
_len = DEFAULT_LEN;
_val_len = 0;
_str = new char[_len];
memset(_str, 0, _len);
return;
}
_val_len = strlen(str);
_len = _val_len + 1;
_str = new char[_len];
memset(_str, 0, _len);
for (int i = 0;i < _val_len; i++)
{
_str[i] = str[i];
}
}
Mstring::Mstring(const Mstring& src)
{
_val_len = strlen(src._str);//_val_len = src._val_len
_len = _val_len + 1;
_str = new char[_len];
memset(_str, 0, _len);
for (int i = 0; i < _val_len; i++)
{
_str[i] = src._str[i];
}
}
Mstring& Mstring::operator=(const Mstring& src)
{
//防止自赋值
if (&src == this)
{
return *this;
}
//删除所有原来的数据
delete[]_str;
//赋值 防止浅拷贝
_val_len = strlen(src._str);//_val_len = src._val_len
_len = _val_len + 1;
_str = new char[_len];
memset(_str, 0, _len);
for (int i = 0; i < _val_len; i++)
{
_str[i] = src._str[i];
}
}
Mstring::~Mstring()
{
delete[]_str;
}
void Mstring::push_back(char c)
{
if (full())
{
revert();
}
_str[_val_len] = c; //存储的实际数据长度就是最后一个要插入的元素的位置
_val_len++;
}
void Mstring::pop_back()
{
if (empty())
{
return;
}
_val_len--;
}
char Mstring::back()const
{
if (empty())
{
return 0;
}
return _str[_val_len - 1];
}
char Mstring::front()const
{
if (empty())
{
return 0;
}
return _str[0];
}
bool Mstring::empty()const
{
return _val_len == 0;
}
Mstring Mstring::operator+(const Mstring& str)
{
char* p;
int len = _val_len + str._val_len;
p = new char[len];
memset(p, 0, len);
//进行数据的拷贝 将两个字符串的数据拼接起来
//先加自己的数据 在从后面加上第二个字符串的数据
int i = 0; //i要声明在外面 下一个循环也要使用
for (; i < _val_len; i++)
{
p[i] = _str[i];
}
for (int j = 0; j < str._val_len; j++)
{
p[i] = str._str[j];
}
return p;
}
char& Mstring::operator[](int pos)
{//返回引用 便于在外界进行修改
return _str[pos];
}
char Mstring::operator[](int pos)const
{
return _str[pos];
}
int Mstring::size()const
{
return _val_len;
}
bool Mstring::full()const //判满
{
return _val_len == _len-1;
// _len-1 减去'\0'的位置
}
void Mstring::revert()//扩容
{
_len = _len << 1; //向左挪一位 相当于乘以2
char* p = new char[_len];
memset(p, 0, _len);
//将原来的数据拷贝过来
for (int i = 0; i < _val_len; i++)
{
p[i] = _str[i];
}
//防止内存泄露 删除原来的str
delete[]_str;
//重新指向扩容好的数据
_str = p;
}
ostream& operator<<(ostream& out, const Mstring& str)
{
for (int i = 0; i < str.size(); i++)
{
cout << str[i];//重载的中括号 常函数的[]
}
cout << endl;
return out;
}
istream& operator>>(istream& in, Mstring& str)
{
char tmp[1024];
in >> tmp;
str = tmp;
return in;
}
mstring 写时拷贝
当多个对象同时拥有同一块内存时,每个对象都只有读取的权限
如果有某个对象需要改动这一块内存的时候,就给该对象拷贝出一份独有的内存
不能修改共有的这块内存
- 优点:
- 减少内存的消耗 :拷贝构造时新产生的对象如果从开始到死亡都不会对原来的对象进行修改 则就可以直接指向原来对象的空间地址,节省需要新开辟出的空间
- 节省时间:新对象不用new的这一步 则在最后就也不需要delete这一步,节省了时间
调用引用计数,判断该对象是否能对进行析构
引用计数放的位置:在_str里面多开辟四个字节用来存放引用计数