C++----模拟实现string

模拟实现string,首先我们要知道成员变量有哪些:

cpp 复制代码
    class _string
    {
    private:
		char* _str;
		size_t capacity;//空间有多大
		size_t size;//有效字符多少

		const static size_t npos;
		
	};


const size_t _string::npos=-1;//static在外面定义不需要带static,npos表示最大位置

接着写构造函数,在string中,初始化方式有无参的,有用字符串初始化的,这就要求我们写一个带缺省参数的默认构造函数:

cpp 复制代码
string(const char* str="")
    :capacity(strlen(str)),
    size(capacity)
{
    _str=new char[capacity+1];
    strcpy(_str,str);
}
//为什么用"",因为它代表了\0,用它初始化再合适不过了
//为什么不用'\0'呢?因为这是一个char*,用'\0'就会用他的ASCII码值初始化
//为什么不用nullptr呢?因为在后面可能会用到_str的解引用,解引用空指针要出问题的

接下来写拷贝构造

cpp 复制代码
string(const string& s)
{
    _str=new char[s.capacity+1];
    capacity=s.capacity;
    size=s.size;
    strcpy(_str,s._str);
}

赋值符号重载

cpp 复制代码
//与单纯的拷贝构造不一样,复制重载原string对象一般都会有原始空间,要释放原始空间
const string& operator=(const string& s)
{
    //最重要的一点!一定要检查自赋值,不检查的话会导致空间释放使用未分配的空间
    if(this==&s)
        return *this;


    //并且释放原始空间和开辟新空间是有顺序的,开辟新空间一定要放在前面
    //避免开辟新空间失败导致原来空间也没有了!
    char *new_ptr=new char[s.size+1];
    strcpy(new_ptr,s._str);
    delete[]_str;
    _str=new_str;
	capacity = s.capacity;
	size = s.size;
	return *this; 
}

如果我们要打印string对象的字符串呢?在没有重载流提取符号的情况下:

cpp 复制代码
const char* c_str() const
{
    return _str;
}

开始定义增删查改部分;增:有push_back、append、+=、insert,直接先定义insert,其他的都可以复用insert函数,insert有插入字符版本和字符串版本:

cpp 复制代码
void reserve(size_t n)
{
    if(capacity<n)
    {
        char* new_ptr=new char[n+1];
        strpy(new_ptr,_ptr);
        delete[]_str;
        _str=new_ptr;
        capacity=n;
    }
}


void resize(size_t n,char ch='\0')//给一个缺省参数
{
    //小于size实质上就是删除多余的字符
    if(n<size)
        _str[n]='\0'
    else
    {
        if(n>capacity)
            reserve(n);
        for(int i=size;i<n;i++)
        {
            _str[i]=ch;
        }
        _str[n]='\0';
    }
    size=n;
}


//插入字符版本
string& insert(size_t pos, char ch)
{
    assert(pos<=size);
    int len=size+1;
    if(len>capacity)
        reserve(len);
    unsigned int end = size+1;

    //unsigned int end = size;
	//while (pos <= end)  //头插有bug,遇到unsigned<=某数要小心,容易最大化
	//{
	//	_str[end + 1] = _str[end];
	//	end--;
	//}

    //\0直接被处理,无需再管\0
	while (pos < end) //有bug,遇到unsigned<=某数要小心,容易最大化,unsigned容易减到-1成最大的
	{
	    str[end] = _str[end-1];
		end--;
	}
	_str[pos] = ch;
	size += 1;

	return *this;
}


//插入字符串版本  本质上从挪一个位置到要挪n个位置的区别
string& insert(size_t pos, const char* str)
{
    assert(pos<=size);
    int len=size+len(str);
    if(len>capacity)
        reserve(len);
    unsigned int end = size+len(str);


    //\0直接被处理,无需再管\0
	while (pos+len-1 < end) //有bug,遇到unsigned<=某数要小心,容易最大化,unsigned容易减到-1成最大的
	{
	    str[end] = _str[end-len(str)];
		end--;
	}
	_str[pos] = ch;
	size += 1;

	return *this;
}

append、+=、push_back直接复用:

cpp 复制代码
		string& operator+=(const char* str)
		{
			insert(size,str);
			return *this;
		}

		string& operator+=(char ch)
		{
			insert(size,ch);
			return *this;
		}


		void push_back(const char ch)
		{
			insert(size,ch);
		}

		void append(const char* str)
		{
			insert(size,ch);
		}

查改:

cpp 复制代码
const char& operator[](int pos)const //一般情况不修改对象内容的,都用const修饰,既考虑了const对象调用,又考虑了非const调用,如果有特殊需要可以都实现,调用时会自动识别
{
    assert(pos<size);
    return *(_str+pos);
}

char& operator[](int pos) //用引用返回可以直接修改
{
    assert(pos<size);
    return *(_str+pos);
}

size_t find(char ch, int pos) const
{
    assert(pos<size);
    while(_str[pos]!=ch)
    {
        if(pos>=size)
            break;
        pos++;
    }
    if(pos==size)
        return npos;
    else
        return pos;
}

char* find(const char* str, int pos)
{
    assert(pos<size);
    char* poss=strstr(_str+pos,str)
    return poss;
}

const char* find(const char* str, int pos) const
{
    assert(pos<size);
    char* poss=strstr(_str+pos,str)
    return poss;
}

迭代器的实现

cpp 复制代码
class _string
{
    typedef char* iterator;
    typedef const char* const_iterator;
    //string这种物理内存连续的可以这么定义指针
    //一定要定义const迭代器 要保证权限不会放大,以及后续一致性问题,不能const字符串的指针能修改                字符串,这就扯淡了


    iterator begin()
    {
        return _str;
    }

    const_iterator begin() const
    {
        return _str;
    }

    iterator end()
    {
        return _str+size;
    }

    const_iterator end() const
    {
        return _str+size;
    }
}

//范围for就是用的迭代器,要想支持范围for遍历就必须定义迭代器begin(),end(),一个字符都不能差。

删:

cpp 复制代码
void erase(size_t pos=npos, int n)
{
    assert(pos<size)
    if(pos+n>size)
        _str[pos]='\0';
        size-=n;
    else
    {
        int start=pos;
        int end=n+pos;
        while(start<=end)
        {
            _str[start]=_str[start+n];
            start++;
        }
        size-=n;
    }

}

重载流提取流插入运算符,在类外重载:

cpp 复制代码
ostream& operator<<(ostream& out, const string& s)
{
    for(auto e: s)
        out<<e;
    return out;
}



//流输入要考虑的问题就多了,要考虑效率问题,以及普通的in不处理换行符的问题。
istream& operator>>(stream& in, string& s)
{
    //引入内存池
    char tmp[128]={'\0'};
    ch=in.get();//可以接收换行符,空格符,如果只in>>,不会接收
    int i = 0;
    while(ch !=' ' and ch!='\n')
    {
        if(i==128)
            s+=tmp;
            i=0;
            memset(tmp,'\0',128);
        tmp[i++]=ch;
        ch=in.get();
    }
    s+=tmp;
    return in; 
}

这么写,其实有问题,输入时之前的旧内存没有释放掉:

cpp 复制代码
//流输入要考虑的问题就多了,要考虑效率问题,以及普通的in不处理换行符的问题。
istream& operator>>(stream& in, string& s)
{
    s= string();//清空内存
    

    //引入内存池
    char tmp[128]={'\0'};
    ch=in.get();//可以接收换行符,空格符,如果只in>>,不会接收
    int i = 0;
    while(ch !=' ' and ch!='\n')
    {
        if(i==128)
            s+=tmp;
            i=0;
            memset(tmp,'\0',128);
        tmp[i++]=ch;
        ch=in.get();
    }
    s+=tmp;
    return in; 
}
相关推荐
球求了26 分钟前
C++:继承机制详解
开发语言·c++·学习
张槊哲1 小时前
函数的定义与使用(python)
开发语言·python
北辰浮光1 小时前
[Mybatis-plus]
java·开发语言·mybatis
超爱笑嘻嘻1 小时前
shared_ptr八股收集 C++
c++
我想进大厂1 小时前
图论---朴素Prim(稠密图)
数据结构·c++·算法·图论
我想进大厂1 小时前
图论---Bellman-Ford算法
数据结构·c++·算法·图论
光而不耀@lgy2 小时前
C++初登门槛
linux·开发语言·网络·c++·后端
lkbhua莱克瓦242 小时前
用C语言实现——一个中缀表达式的计算器。支持用户输入和动画演示过程。
c语言·开发语言·数据结构·链表·学习方法·交友·计算器
Mr__Miss2 小时前
面试踩过的坑
java·开发语言
啊丢_2 小时前
C++——Lambda表达式
开发语言·c++