【C++】模拟实现string类

简易写法:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<vector>
#include<assert.h>
using namespace std;
class String{
private:
	char* _data;
	size_t _size;
public:
	String()//这个是默认构造,默认就是一个空
		: _data(new char[1])
	{
		*_data = '\0';//解引用
	}

	String(const char* data)//参数const
		:_data(new char [strlen(data)+1])
		,_size(strlen(data))
	{
		strcpy(_data, data);
	}


	String(const String& s)//参数const
	{
		String(s._data);
	}

	void Swap(String& s){//注意大写第一个字母
		swap(_data, s._data);
		swap(s._size, s._size);
	}

	String& operator=(String s)//参数值
	{
		Swap(s);
		return *this;
	}

	String(String&& s){
		_data = s._data;
		s._data = nullptr;//移动构造记得置空
		_size = s._size;
	}

	String& operator=(String&& s){//直接交换
		if (_data){
			delete[] _data;
			_data = nullptr;
		}
		Swap(s);
		return *this;
	}

	~String(){
		if (_data){
			delete[] _data;
		}
		_size = 0;
		
	}

	int Size(){
		return _size;
	}

	const char* c_str()const {//const!!!!
		return _data;
	}

	//上面的是基础,在可以增加[],==,<
	char& operator[](size_t pos){
		assert(pos < _size);
		return _data[pos];
	}

	
};
bool operator==(const String& s1, const String& s2){
	return !strcmp(s1.c_str() ,s2.c_str());//返回值等于0就是相等
}


bool operator<(const String& s1, const String& s2){
	int a=strcmp(s1.c_str(), s2.c_str());//返回大于等于0就不是小于
	if (a<0){
		return true;
	}
	return false;
}
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<assert.h>
#include<stdlib.h>
#include<string.h>
using namespace std;
class String{
private:
	size_t _size;  //无符号整数代表存储的大小
	size_t _capacity;
	char* _data; //具体用来存储的内存指针
	static const size_t npos;//const static可以类内定义

public:
	typedef char* iterator;
	typedef const char* const_iterator;//代表着是一个指针指向了不可变的变量
	iterator begin(){
		return _data;
	}
	const_iterator begin() const{ //const可以作为重载的标志(返回值不可以)
		return _data;
	}
	iterator end(){	//刚好是最后一个有效的下一个
		return _data + _size;
	}
	const_iterator end()const{
		return _data + _size;
	}

//这个应该写一个无参构造当默认构造
	String(const char* str = '\0')//一般是常量字符串来赋值的const
		:_size(strlen(str))//strlen是不包括\0的字符串大小
		, _capacity(_size)
		, _data(new char[strlen(str) + 1])//new []用来初始化多个空间[个数]--这里要有/0
	{
		strcpy(_data, str);
	}

	void Swap(String& str){
		swap(_data, str._data);
		swap(_size, str._size);
		swap(_capacity, str._capacity);

	}
	String(const String& str)//拷贝构造底层也是调用构造
		:_size(0)//等会用来交换这些就置空
		, _capacity(0)
		, _data(nullptr)
	{
		cout << "拷贝构造" << endl;
		String tmp(str._data);//随便来个第三方变量创造出空间和内容
		Swap(tmp);//交换后tmp就为空了
	}

	~String(){
		if (_data){//一定要判断,否则释放空指针
			delete[] _data;//所有的都是new[]
		}
		_data = nullptr;//不用的最好变成空指针
		_capacity = _size = 0;

	}
	bool operator==(const String& str){//这个传一个参数返回一个bool
		if (_data == str._data&&_size == str._size&&_capacity == str._capacity)
			return true;
		return false;
	}

	//赋值运算符重载的返回值是引用提高效率,不加也可以过,
	//+法运算符写在类外,返回的是值,如果返回引用就是返回局部变量的值,返回值的话会返回匿名对象(拷贝构造)
	//利用传值调用拷贝构造,就不用新变量了
	//弊端是不能加const,cosnt修饰的不能swap
	String& operator=(String str){
		Swap(str);
		return *this;
	}

	/*String& operator=(const String& str){//形参也不能是const
		if (*this == str){
			return *this;
		}
		String tmp(str);//调用拷贝构造,拷贝构造底层是通过str的_data调用构造,不具有常性
		Swap(tmp);//可以用来交换
		return *this;
	}*/

	char& operator[](size_t a){//取下标要求可以通过下表修改所以是返回引用
		assert(a < _size);//下标越界是需要assert的警告,assert内部是正确的范围
		return _data[a];
	}

	const char& operator[](size_t a)const{
		assert(a < _size);
		return _data[a];
	}

	void reserve(size_t ch){//增容,就是修改_capacity的大小,参数就是需要改变的大小
		if (_capacity < ch){//小于就不动
			char* newp = new char[ch + 1];//这里有个+1没写 ch表示有效字符的最大个数不包括\0

			//拷贝存数据的内容
			strcpy(newp, _data);
			delete[] _data;//释放原有内容,避免内存泄露
			_data = newp;
			_capacity = ch;
		}
	}

	void resize(size_t ch, const char& a = '\0'){//改变_size的大小,不足用指定的符号补齐
		if (_capacity < ch)//先看容量
			reserve(ch);
		if (_size < ch)
			memset(_data + _size, a, sizeof(char)*(ch - _size));//太多了才填充字符,这个可不会填充_capacity
		_size = ch;//修改size的大小
		//忘记\0
		_data[_size] = '\0';//数据一定要有结束标志
	}


	void push_back(const char&a = '\0'){
		if (_size == _capacity){//证明满了需要增容
			//三目运算符顺序
			size_t newcapacity = _capacity == 0 ? 15 : 2 * _capacity;
			reserve(newcapacity);//增容
		}
		_data[_size++] = a;//size没有存\0
		_data[_size] = '\0';
	}

	void append(const char* str){//插入新的字符数组
		if (_capacity < (strlen(str) + _size)){
			//等于甚至也不需要增容。因为reserve自动申请多一个存储\0,而_capacity隐藏这个
			//构造函数也会默认多申请一个空间用来存储\0
			reserve(strlen(str) + _size);
		}
		memcpy(_data + _size, str, sizeof(char)*strlen(str));
		//忘记更新size
		_size += strlen(str);
		_data[_size] = '\0';//注意新增
	}

	//+=需要写在类内。返回引用,提高效率,返回值需要调用一次拷贝构造
	String& operator+=(const String& str){
		cout << "operator +=" << endl;
		append(str._data);
		return *this;
	}

	String& operator+=(const char* str){
		append(str);
		return *this;
	}

	String& operator+=(const char& str){
		push_back(str);
		return *this;
	}

	void insert(size_t pos, const char& ch){//pos的下一个位置插入
		assert(pos <= _size);//可以等于,忘写了
		//size代表的是元素个数
		if (_size == _capacity){
			size_t newc = _capacity == 0 ? 1 : 2 * _capacity;
			reserve(newc);
		}

		size_t idx = _size;
		while (idx>pos-1){//pos的位置也要移动
			_data[idx+1] = _data[idx];
			--idx;
		}
		/*size_t idx = _size + 1;//从后向前移动,包括\0
		while (idx>pos){
			_data[idx] = _data[idx - 1];
			idx--;
		}*/
		_data[pos] = ch;
		++_size;
	}

	void insert(size_t pos, const char* ch){
		assert(pos <= _size);
		size_t len = strlen(ch);
		if (len + _size > _capacity){
			reserve(len + _size);
		}
		size_t idx = _size + len;

		
		while (idx>pos+1){
			_data[idx] = _data[idx - len];
			idx--;
		}
		memcpy(_data + pos, ch, sizeof(char)*len);//不能strcpy-->会拷贝\0
		_size += len;
	}

	void earse(size_t pos, size_t len = npos){
		assert(pos <= _size);
		//如果没有指定删除的大小或者需要全部删除后面的
		if (pos + len >= _size || len == npos){
			_size = pos;
			_data[_size] = '\0';

		}
		else{
			size_t idx = pos + len;
			while (idx <= _size){
				_data[idx - len] = _data[idx];
				++idx;
			}
			_size -= len;
		}
	}

	size_t find(const char* ch, size_t pos = 0){//pos是从这个位置之后查找
		assert(pos < _size);
		char* strpos = strstr(_data + pos, ch);
		if (strpos){
			return strpos - _data;//返回找到的位置(指针相减)
		}
		return npos;
	}

	String substr(size_t pos, size_t len = npos){//创建子串
		assert(pos < _size);
		if (pos + len >= _size || len == npos){
			return String(_data + pos);//pos是一个数字,指针加数字是指针
		}
		else{
			char* newc = new char[len + 1];
			//char *newc=[len+1];栈申请需要高级编译器才能识别
			memcpy(newc, _data + pos, sizeof(char)*len);
			newc[len] = '\0';
			delete[] newc;//这里不写会内存泄漏,写了会报错
			return String(newc);
		}
	}

	size_t size()const{
		return _size;
	}

	size_t capacity()const{
		return _capacity;
	}


	const char* c_str() const{
		return _data;
	}
	friend ostream& operator<<(ostream& out, const String& str);
	friend istream& operator>>(istream& cin, String& str);
};

const size_t String::npos = -1;

//以下属于普通函数,重载函数,不能通过str.operator<<来访问
//只能通过普通函数的访问形式访问
String operator+(const String& a, const String& b){//普通函数不能加string::
	String str(a);  //拷贝构造需要const,否则报错
	//因为const可以接受const和非const,非const只能接受const
	str += b;
	return str;
}
String operator+(const String& a, const char* b){
	String str(a);
	str += b;
	return str;
}
String operator+(const String& a, const char& b){
	String str(a);
	str += b;
	return str;
}

bool operator<(const String& str1, const String& str2){
	int a = strcmp(str1.c_str(), str2.c_str());//1>2--大于0 否则小于0
	if (a<0){
		return true;
	}
	return false;
}

bool operator==(const String& str1, const String& str2){
	int a = strcmp(str1.c_str(), str2.c_str());
	if (a == 0){
		return true;
	}
	return false;
}

bool operator!=(const String& str1, const String& str2){
	return !(operator== (str1, str2));
}

//这里是借助迭代器来实现的打印,没有访问类的私有成员,不用写友元
ostream& operator<<(ostream& out, String& str){
	for (const auto ch : str){
		out << ch;
	}
	return out;
}

//相比于输出流简单地输出,输入流相当于尾插string
istream& operator>>(istream& cin, String& str){
	char ch;
	while ((ch = cin.get()) != EOF){
		if (ch == ' ' || ch == '\0')
			break;
		str += ch;
	}
	return cin;
}

void printffor(const String& str){//const是为了也同时可以打印const的字符串
	//形参const走的就是const的迭代器
	for (const char& a : str){   //const_it
		cout << a;
	}
	cout << endl;
}

void printffor2(const String& str){
	String::const_iterator it = str.begin();
	while (it != str.end()){
		cout << *it << " ";
		++it;
	}
	cout << endl;
}

void test(){
	String str1 = "hello";
	String str2 = " world";

	
	cout << str1 << endl;
	cin >> str2;
	cout << str2 << endl;
}

int main(){
	test();
	system("pause");
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值