模拟实现string类

string类的模拟实现

本文只是对部分函数进行分析和代码展示,具体代码我已经上传到GitHub上面了

GitHub链接:https://github.com/Sveter/CPlusPlus

  • string类
  1. string是表示字符串的字符串类
  2. 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。
  3. string在底层实际是:basic_string模板类的别名,typedef basic_string<char, char_traits, allocator>string;
  4. 不能操作多字节或者变长字符的序列。
模拟实现
  • String.h
#ifndef __STRING_H__
#define __STRING_H__

#include <iostream>
#include <string.h>
unsig namespace std;

class String
{
//为了实现迭代器
public:
	typedef char* Iterator;
public:
    //默认成员函数
    //构造函数以及构造函数的重载
    String()
    {}
    String(const char* str)
	{
		if (nullptr == str)
		{
			str = "";
		}
		_size = strlen(str);
		_str = new char[_size + 1];
		_capacity = _size;

		strcpy(_str, str);
	}
	String(const char* str, size_t size)
	{
		if (size < 0)
		{
			cout << "size error" <<endl;
			exit(EXIT_SUCCESS);
		}
		_size = size;
		_str = new char[_size + 1];
		_capacity = _size;
		strncpy(_str, str, size);
		if (size < strlen(str))
		{
			_str[_size] = 0;
		}
	}
    //拷贝构造函数
	//采用深拷贝的传统写法
	String(const String& s)
		:_str(new char[s._capacity+1])
		,_capacity(s._capacity)
		,_size(s._size)
	{
		strcpy(_str, s._str);
	}
	//深拷贝的现代版写法
	//String(const String& s)
	//{
	//	String strTmp(s._str);
	//	swap(_str, strTmp);
	//}
	//赋值运算符的重载
	String& operator=(const String& s)
	{
		if (&s != this)
		{
			char* pStr = new char[s._capacity + 1];
			strcpy(pStr, s._str);
			delete[] _str;
			_str = pStr;
			_size = s._size;
			_capacity = s._capacity;
		}
		return *this;
	}
	//析构函数
	~String()
	{
		if (_str)
		{
			delete[] _str;
			_str = nullptr;
			_capacity = 0;
			_size = 0;
		}
	}
    //成员函数
    //1. 迭代器
    Iterator Begin();
	Iterator End();
	  //反向查找
	Iterator RBegin();
	Iterator REnd();
	
	//2. 增删改查
	void PushBack(char c); //尾插字符
	void Append(const char* str); //追加字符串
	String& Insert(size_t pos, char c); //在指定位置插入字符
	String& Insert(size_t pos, const char* str); //在指定位置插入字符串
	String& Erase(size_t pos, size_t len); 	//删除指定位置,指定长度的内容
	void Resize(size_t newSize, char c = '0'); //调整大小
	void Reserve(size_t newCapacity); //扩容
	int Size()const; //查询字符串大小
	int Capacity()const; //查询容量
	bool Empty()const; //判断是否为空
	void Clear(); //清空
	int Find(char c, size_t pos = 0); //查找字符第一次出现的位置
	int rFind(char c); //从后往前查找字符第一次出现的位置
	void Swap(String& s); //字符串交换
	String SubStr(size_t pos, size_t size); //截取字符串
	const char* C_Str()const; //以C的形式输出
	
	//3. []的重载
	char& operator[](size_t index);
	const char& operator[](size_t index)const;
	
	//4. 运算符的重载
	bool operator<(const String& s);
	bool operator<=(const String& s);
	bool operator>(const String& s);
	bool operator>=(const String& s);
	bool operator==(const String& s);
	bool operator!=(const String& s);
	String operator+(char c); //+符号的重载
	String operator+(const char* str)
	String operator+=(char c) 	//+=符号的重载
	String operator+=(const char* str)
	
	//<<&>>的重载
	friend ostream& operator<<(ostream& _cout, const String& s)
	friend istream& operator>>(istream& _cin, String& s)
private:
    char* _str;
	size_t _capacity;
	size_t _size;
    //find函数没找到的返回值
    const static int npos;
};

const int String::npos = -1;

#endif //!__STRING_H__
  • 在这里我仅对部分成员函数分析

  • 1. 构造函数和拷贝构造函数

  1. 构造函数是创建一个对象,然后给_str变量申请内存,再设置好_size和_capacity变量
  2. 拷贝构造函数这里分为浅拷贝和深拷贝,我们用深拷贝,在编译器中默认是浅拷贝,最终导致的问题是,共用同一块内存空间,在释放时同一块空间被释放多次而引起程序崩溃

浅拷贝和深拷贝

在这里插入图片描述

  • 2. 赋值运算符重载

赋值运算符重载和拷贝构造函数存在同样的问题,在这里我们用的也是深拷贝的方式

  • Insert()
  1. 先判断是否需要扩容
  2. 把pos位置之后的字符都向后挪一位,在pos位置插入指定字符
String& Insert(size_t pos, char c)
	{
		if (_size + 1 >= _capacity)
		{
			Reserve(_capacity * 2);
		}
		_str[_size + 1] = '\0';
		for (int i = _size; i > pos; i--)
		{
			_str[i] = _str[i - 1];
		}
		_str[pos] = c;
		++_size;
		return *this;
	}
  • Erase()

第一种,pos位置之后的字符个数大于n,pos之后全删

第二种,pos位置之后的字符个数小于n,则我们需要在pos之后删除n个元素

String& Erase(size_t pos, size_t len)
	{
		//删除的数据未超过字符串长度
		if (pos + len <= _size)
		{
			while (_str[pos + len] != '\0')
			{
				_str[pos] = _str[pos + len];
				pos++;
			}
			_str[pos] = _str[pos + len];
			_size = strlen(_str);
		}
		else
		{
			_str[pos] = _str[_size];
			_size = strlen(_str);
		}
		return *this;
	}
测试
void TestString1()
{
	String s1;
	String s2("hello world");
	String s3(s2);
	s1 = s3;
	cout << s1 << endl;
	cout << s2 << endl;
	cout << s3 << endl;
}
void TestString2()
{
	String s1("hello");
	s1.PushBack(' ');
	s1.PushBack('1');
	s1.Append("31");
	s1 += '4';
	cout << s1 << endl;
	cout << s1.Size() << endl;
	cout << s1.Capacity() << endl;
	// 利用迭代器打印string中的元素
	auto it = s1.Begin();
	while (it != s1.End())
	{
		cout << *it++;
	}
	cout << endl;
	String s2("hello world!!!");
	s1.Swap(s2);
	cout << s1 << endl;
	cout << s2 << endl;
}

void TestString3()
{
	String s("hello");
	cout << s << endl;
	cout << s.Size() << endl;
	cout << s.Capacity() << endl;
	s.Resize(10, 'a');
	cout << s << endl;
	cout << s.Size() << endl;
	cout << s.Capacity() << endl;
	s.Resize(20);
	cout << s << endl;
	cout << s.Size() << endl;
	cout << s.Capacity() << endl;
	s.Resize(5);
	cout << s << endl;
	cout << s.Size() << endl;
	cout << s.Capacity() << endl;
	s.Reserve(50);
	cout << s << endl;
	cout << s.Size() << endl;
	cout << s.Capacity() << endl;
}

void TestString4()
{
	String s1("abcdefg");
	String s2 = s1;
	cout << s1 << endl;
	s1.Insert(2, 'h');
	cout << s1 << endl;
	s1.Insert(2, "123");
	cout << s1 << endl;
	s2.Erase(2, 5);
	cout << s2 << endl;
}

void TestString5()
{
	String s1 = "abcdef";
	String s2 = "abcdh";
	cout << (s1 < s2) << endl;
	cout << (s1 > s2) << endl;
	cout << (s1 == s2) << endl;
	cout << (s1 != s2) << endl;
	cout << (s1 >= s2) << endl;
	cout << (s1 <= s2) << endl;
}

int main()
{
	cout << "Test1: 默认成员函数" << endl;
	TestString1();
	cout  << endl;
	cout << "Test2: Iterators + Modifiers" << endl;
	TestString2();
	cout << endl;
	cout << "Test3: Capacity" << endl;
	TestString3();
	cout << endl;
	cout << "Test4: Modifiers" << endl;
	TestString4();
	cout << endl;
	cout << "Test5: 比较" << endl;
	TestString5();
	cout << endl;

	return 0;
}

在这里插入图片描述

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值