C++——模拟实现string

阅读: 评论:0

C++——模拟实现string

C++——模拟实现string

目录

  • 一、定义my_string类
  • 二、成员函数
    • (一)构造函数
    • (二)析构函数
    • (三)拷贝构造
    • (四)赋值运算符重载
  • 三、迭代器
  • 四、Capacity
    • (一)获取string容量
    • (二)改变容量
  • 五、元素访问
    • (一)[]运算符重载
  • 六、string修改
    • (一)插入insert
    • (二)删除erase
    • (三)尾插push_back
    • (四)尾删pop_back
    • (五)追加插入append
    • (六)+=运算符重载
  • 七、关系运算符重载
  • 八、查找
  • 九、输入输出运算符重载(不是成员函数)
    • (一)输入运算符重载
    • (二)输出运算符重载

一、定义my_string类

  此处标明:以下成员函数都是写在my_list类内部的

#include<iostream>
#include<assert.h>
#include<string>using namespace std;class my_string{
private:char* _ptr;    //字符串size_t _size;       //有效字符个数size_t _capacity;      //容量static size_t npos;     //size_t类型中最大数(表示-1)
public://交换void Swap(my_string& str){swap(_ptr, str._ptr);swap(_size, str._size);swap(_capacity, str._capacity);}//成员函数及其他功能在下面实现
};
size_t my_string::npos = -1;

二、成员函数

(一)构造函数

  对象中需要额外的资源,则显示写出构造函数;
  构造函数参数缺省一个空字符串,写成一个默认构造;

	my_string(char* str = ""){_size = strlen(str);_capacity = _size;_ptr = new char[_size + 1];    //开一个_size+1的空间,给''留一个位置strcpy(_ptr, str);}

  构造函数中申请一个_size+1的空间,用来将字符串拷贝到对象中,留出一个 的位置;

(二)析构函数

  对象中有额外的资源开销,需要显示写出析构函数;

	~my_string(){//对象资源不为nullptr,则进行销毁if (_ptr){delete[] _ptr;_ptr = nullptr;_size = 0;_capacity = 0;}}

(三)拷贝构造

  1、传统写法

	my_string(const my_string& str):_ptr(new char[str._capacity + 1])   //此处开了str._capacity + 1的空间,是因为_capacity是最大有效容量,不包括'', _size(str._size), _capacity(str._capacity){strcpy(_ptr, str._ptr);}

  2、简便写法
  简便写法就是先将对象本身初始化为空,再通过构造函数创建一个临时的对象,与对象本身交换以达到拷贝的效果;

	my_string(const my_string& str):_ptr(nullptr)     //此处让_ptr = nullptr是为了销毁临时对象时不会造成销毁错误, _size(0), _capacity(0){//创建一个临时对象my_string tmp(str._ptr);//与临时对象进行交换Swap(tmp);}

  _ptr(nullptr) 这个得目的是临时对象在调用析构的时候也可以正常运行,如果不初始化为 nullptr 的话,则_ptr会指向内存中的地址,那么再析构销毁时就会出现问题;

(四)赋值运算符重载

  对象有资源开销,则显示写出赋值运算符重载函数,完成资源的深拷贝;
  1、传统写法

	my_string& operator=(const my_string& str){//不是自己给自己赋值,则进入判断if (this != &str){//开空间char* tmp = new char[str._capacity + 1];//释放原有空间delete[] _ptr;//拷贝strcpy(tmp, str._ptr);//改变指针指向,完成深拷贝_ptr = tmp;_size = str._size;_capacity = str._capacity;}return *this;}

  2、简便写法

	my_string& operator=(my_string str){Swap(str);return *this;}

  这种写法的深拷贝在传参的时候就已经进行了,参数接收时用了一个拷贝构造拷贝了要赋值的对象,再将其与被赋值对象进行资源交换,则完成了深拷贝赋值;

三、迭代器

  迭代器底层上其实就是指针,不过是将指针起了一个别名叫iterator,所以实现时也就是用指针实现的;
  begin其实就是获取第一个元素的地址;end是获取最后一个元素的下一个位置的地址;
  需要注意的是const迭代器必须用const来修饰函数;

	//迭代器iteratortypedef char* iterator;typedef const char* const_iterator;iterator begin(){return _ptr;}iterator end(){return _ptr + _size;        //指向最后一个索引的下一个位置}const_iterator begin() const{return _ptr;}const_iterator end() const{return _ptr + _size;}const_iterator cbegin() const{return _ptr;}const_iterator cend() const{return _ptr + _size;}

四、Capacity

(一)获取string容量

  1、获取有效元素个数:size()

size_t size()
{return _size;
}

  2、获取最大有效元素容量:capacity()

size_t capacity()
{return _capacity;
}

  3、判空

	bool empty() const{if (_size == 0)return true;return false;}

(二)改变容量

  1、扩容:reserve()
    当容量不够时需要扩容,需要重新开辟一块更大的空间;

	void reserve(size_t n){if (n >= _capacity){//开空间char* tmp = new char[_capacity + 1];//拷贝strcpy(tmp, _ptr);//删除原有空间delete[] _ptr;//改变指向_ptr = tmp;_capacity = n;}}

  2、改变有效元素的个数:resize()
   改变容量resize通常有以下几方面的情况:

	(1)n < _size:缩容(2)_size < n < _capacity:增容 + 赋值(3)n > _capacity:扩容 + 增容 + 赋值
	void resize(size_t n, char ch = ''){if (n > _size){if (n > _capacity){reserve(n);}memset(_ptr + _size, ch, (n - _size) * sizeof(char));}_size = n;_ptr[_size] = '';}

五、元素访问

(一)[]运算符重载

	char& operator[](int i){//判断位置是否越界assert(i < _size);return _ptr[i];}const char& operator[](int i) const{assert(i < _size);return _ptr[i];}

六、string修改

(一)插入insert

  1、插入单个字符
    在pos位置的前面插入一个字符;
    插入时,将待插入位置后面的字符从后向前依次向后移动;

	my_string& insert(size_t pos, char ch){//判断访问是否越界assert(pos <= _size);//判断容器是否满了if (_size == _capacity){size_t new_capacity = _capacity == 0 ? 15 : 2 * _capacity;reserve(new_capacity);}size_t end = _size;//从后向前移动元素while (end > pos){_ptr[end] = _ptr[end - 1];end--;}_ptr[pos] = ch;_ptr[++_size] = '';       //最后需要在_size位置补上‘’return *this;}

  2、插入字符串
    在pos位置前面插入一个字符串;
    插入时,将待插入位置后面的字符从后向前依次向后移动;

	my_string& insert(size_t pos, const char* str){//判断是否越界assert(pos <= _size);size_t len = strlen(str);//判断容器是否满了if (_size + len > _capacity){reserve(_size + len);}size_t end = _size + len - 1;while (end > pos + len - 1){_ptr[end] = _ptr[end - len];end--;}memcpy(_ptr + pos, str, len);_size += len;_ptr[_size] = '';return *this;}

(二)删除erase

  将pos位置向后n个字符删除,pos缺省为0,len缺省为最大值npos(也就是将从pos位置到字符串结尾全部删除);
  删除时,将删除的元素后面的元素从前向后向前移动;

	my_string& erase(size_t pos = 0, size_t len = npos){//判断边界assert(pos < _size);//判断是否是无效删除位置if ((pos + len >= _size) || (len == npos)){_size = pos;_ptr[_size] = '';return *this;}size_t start = pos + len;//从前向后移动位置while (start < _size){_ptr[start - len] = _ptr[start];start++;}_size -= len;_ptr[_size] = '';return *this;}

(三)尾插push_back

	void push_back(char ch){insert(_size, ch);}

(四)尾删pop_back

	void pop_back(){erase(_size - 1);}

(五)追加插入append

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

(六)+=运算符重载

  +=运算会改变原对象的内容,所以返回引用

	my_string& operator+=(const my_string& str){append(str._ptr);return *this;}

七、关系运算符重载

	//<运算符重载bool operator<(const my_string& str){if (strcmp(_ptr, str._ptr) < 0)return true;return false;}//<=运算符重载bool operator<=(const my_string& str){if (*this > str)return false;return true;}//>运算符重载bool operator>(const my_string& str){if (strcmp(_ptr, str._ptr) > 0)return true;return false;}//>=运算符重载bool operator>=(const my_string& str){if (*this < str)return false;return true;}//==运算符重载bool operator==(const my_string& str){if (strcmp(_ptr, str._ptr) == 0)return true;return false;}//!=运算符重载bool operator!=(const my_string& str){if (*this == str)return false;return true;}

八、查找

  1、查找一个字符
    从pos位置开始查找一个字符,pos缺省值为0;
    因为查找时不能修改字符串,所以需要用const来修饰该函数;
    返回c在string中第一次出现的位置

	// 返回c在string中第一次出现的位置size_t find(char ch, size_t pos = 0) const{size_t count = 0;while (count < _size){if (*(_ptr + pos + count) == ch)return count;count++;}return count;}

  2、查找一个字符串
    从pos位置开始查找一个字符串,pos缺省值为0;
    因为查找时不能修改字符串,所以需要用const来修饰该函数;
    返回子串s在string中第一次出现的位置

// 返回子串s在string中第一次出现的位置size_t find(const char* str, size_t pos = 0) const{size_t len = strlen(str);size_t count = 0;while (count < _size - len + 1){size_t i = pos + count;while (i < count + len){size_t j = 0;if (_ptr[i] != str[j])break;i++;j++;}if (i == count + len)return count;count++;}return count;}

九、输入输出运算符重载(不是成员函数)

  输入输出运算符重载函数不是成员函数,不要写到my_string类中;

(一)输入运算符重载

istream& operator>>(istream& _cin, my_string& str)
{char ch;while ((ch = getchar()) != EOF){if (ch == 'n')return _cin;str += ch;}return _cin;
}

(二)输出运算符重载

ostream& operator<<(ostream& _cout, const my_string& str)
{for (const auto& ch : str){_cout << ch;}return _cout;
}

本文发布于:2024-02-02 09:20:41,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170683684242838.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:string
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23