String 类的模拟实现

模拟实现

一: 简单string模拟实现包括4个组成部分:(析构函数,拷贝构造(有传统写法,现代写法),构造函数,赋值运算符(有传统写法,现代写法))
#define _CRT_SECURE_NO_WARNINGS
#include <string>
#include <iostream>
using namespace  std;

class String{
public:	
	//无参构造
	String(char* ptr = " ")
		:_ptr(new char[strlen(ptr) +1]) //初始化列表
	{
		strcpy(_ptr, ptr);
	}
	/*String(const String& str)
		:_ptr(str._ptr)
	{}*/

	// 传统写法: 显示拷贝构造,完成深拷贝: 拷贝对象+资源
	//String(const String& str)
	//	:_ptr(new char[strlen(str._ptr) + 1]) //把空间先开好
	//{
	//	strcpy(_ptr, str._ptr); //将对象进行拷贝过去
	//}
	//拷贝构造现代写法
	String(const String& str)
		:_ptr(nullptr)
	{
		//创建一个局部变量:调用构造函数--->开空间+内容拷贝
		String tmp(str._ptr); //复用了构造函数的逻辑
		swap(_ptr, tmp._ptr);
	}
	//赋值运算符重载
	//String& operator=(const String& str) {
	//	if (this != &str) {
	//	//1.开空间
	//		char* tmp = new char[strlen(str._ptr) + 1];
	//	//2.拷贝资源
	//		strcpy(tmp, str._ptr);
	//	//3.释放原有资源
	//		delete[] _ptr;
	//	//指向新的空间
	//		_ptr = tmp;
	//	}
	//	return *this;
	//}
	//复制运算符重载函数 现代写法
	String& operator=(String str) { //传值过程自动调用构造函数
		swap(_ptr, str._ptr);
		return *this;
	}
	//析构函数             
	~String() {
		if (_ptr) {
			delete[] _ptr;
			_ptr = nullptr;
		}
	}
	
	const char* c_str() const {
	  return _ptr;
	}
private:
	char* _ptr;
};

void test1() {
	String s("123");
	//拷贝构造
	String s2 = s;
	//赋值: operator=
	String s3 = s2;
}
int main () {
	test1();
    system("color A");
    system ("pause");
    return 0;
}

String 类的模拟实现

深拷贝: 成员+资源
string类实现:类似于顺序表实现

#define  _CRT_SECURE_NO_WARNINGS
#include <string>
#include <iostream>
using namespace  std;

class String {
public:

	//迭代器:一种访问容器元素的机制,体现封装的特性,不需要关注容器的实现细节,就可以直接访问(可读可写)元素
	//使用方式类似于指针
	//1.解引用--->获取指向位置的内容
	//2.位置移动--->指向其他位置
	//String 迭代器: 通过char*来实现
	//1.可读可写迭代器:char*
	//2.只读迭代器:const char*
	//3.begin:字符串首地址--->_str
	//4.end:最后一个字符的下一个位置--->_str+_size
	//范围for:通过迭代器实现
	//1.编译器执行操作时,把范围for转化成迭代器的遍历方式
	//2.如果遍历过程中,如果要进行写操作,接收类型需要为引用类型
	typedef char* iterator; //可读可写
	typedef const char* const_iterator; //可写
	//如果执行可读可写的操作就执行
	iterator begin() {
		//第一个元素的位置
		return _str;
	}
	iterator end() {
		//最后一个元素的下一个位置
		return _str + _size;
	}
	//如果执行可读的操作就执行,二者一定要区分开
	const_iterator begin() const {
		//第一个元素的位置
		return _str;
	}
	const_iterator end()  const{
		//最后一个元素的下一个位置
		return _str + _size;
	}
	//1.构造函数
	//无参构造: 假如无参就调用该函数
	String()
		: _str(new char[16]) //开16个空间
		, _size(0)
		, _capacity(0)
	{
		_str[_size] = '\0';
		_capacity = 15;
	}
	//有参构造: 假如有参数就进行调用  有参时一定不能直接将地址进行拷贝过去
	String(const char* str) //表示以字符串作为参数进行初始化
		/*	:_str(str) 如果直接这样进行赋值之后那么,有可能不会被释放掉,因为常量位于代码段,而delete释放堆上的空间
		, _size(strlen(str))
		, _capacity(strlen(str))
		*/
	{
		_size = strlen(str);
		_str = new char[_size + 1]; //

		strcpy(_str, str);
		_capacity = _size;
	}
	//2.拷贝构造
	拷贝构造函数 传统写法 要进行空间的拷贝
	//String(const String& str)  
	//	:_str(new char[str._capacity+1])
	//	,_size(str._size)
	//	, _capacity(str._capacity)
	//
	//{
	//	//深拷贝: 资源拷贝  成员+资源
	//	strcpy(_str, str._str);
	//	cout << "String(const String& str) " << endl;
	//}
	
	//拷贝构造现代写法 完成拷贝构造并且是一种深拷贝
	//不用开空间,体现代码的复用
	//拷贝构造:现代写法
	//1.复用构造函数
	//2.通过构造函数开空间,拷贝内容,最后通过成员和资源的交换,完成拷贝构造的逻辑
	String(const String& str)
		//要给初始化列表 ,假入不给tmp拷贝完之后要调用析构函数
		:_str(nullptr)
		, _size(0)
		, _capacity(0)
	{
		//创建一个临时变量,调用拷贝构造
		String tmp(str._str);  //拷贝构造调用完之后要调析构函数
		Swap(tmp);
	}
	void Swap(String& str) {
		//交换三个成员变量的值即可
		swap(_str, str._str);
		swap(_size, str._size);
		swap(_capacity, str._capacity);
	}
	//深拷贝的交换: 效率很低
	//void Swap(String& str) {
	//	//1.拷贝构造
	//	String tmp=str;
	//	//2.赋值运算符
	//	str = *this;
	//	//3.赋值运算符
	//	*this = str;
	//}
	///
	//3.赋值运算符
	 赋值运算符
	//String& operator=(const String& str) {
	//	if (this != &str) {
	//		//开新的空间
	//		char* tmp = new char[str._capacity + 1];
	//		//把内容放到新的空间里面内容拷贝
	//		strcpy(tmp, str._str);
	//		//释放原有空间 
	//		delete[] _str;

	//		//再把新的空间给他们
	//		_str = tmp;
	//		_size = str._size;
	//		_capacity = str._capacity
	//	}
	//	return *this;
	//}
	//深拷贝   赋值运算符的现代写法
	//拷贝构造:现代写法
	//1.复用构造函数
	//2.通过构造函数开空间,拷贝内容,最后通过成员和资源的交换,完成拷贝构造的逻辑

	//赋值运算符:现代写法
	//1.复用拷贝构造函数
	//2.传参时,通过值传递,调用拷贝构造构造创建局部变量,完成开空间+内容拷贝,最后通过成员和资源的交换,或许新的资源和内容,
	//最终调用局部对象的析构函数,释放原有空间,完成赋值的逻辑
	String& operator=(String str) {  //拷贝构造: (传参进行拷贝构造)
		Swap(str);//拷贝构造的复用
		return *this;
	}
	//string类的简单写法: 构造函数 拷贝构造(现代写法)  赋值运算符(现代写法)    析构函数 这四个就可以完成一个简单的string类的实现
	///
	const char* c_str() const {
		return _str;
	}
	//4.析构函数
	~String() {
		if (_str) {
			delete[] _str; //delete是属于释放堆上的空间
			_size = _capacity = 0;
			_str = nullptr;
		}
		cout << "~String()" << endl;
	}
	//尾插字符操作
	void pushBack(const char& ch) {
		1.检查容量
		//	if (_size == _capacity) {
		//		size_t newC = _capacity == 0 ? 15 : 2 * _capacity;
		//		reserve(newC);
		//	}
		2.尾插操作
		//	_str[_size] = ch;
		3.更新size
		//	++_size;
		//	_str[_size] = '\0';
		insert(_size, ch);
	}
	void reserve(size_t n) {
		if (n > _capacity) {
			//1.开空间+1//存放\0
			char* tmp = new char[n + 1];

			//2.拷贝
			//strcpy(tmp, _str);
			for(int i = 0;i<=_size;i++) {
              tmp[i]=_ptr[i];
           }
 			//3.释放原有空间
			delete[] _str;
			_str = tmp;
			//更新容量
			_capacity = n;
		}
	}
	//第三种遍历方式:operator[]
	char& operator[](size_t pos) {
		if (pos < _size) {
			return _str[pos];
		}
	}
	const char& operator[](size_t pos) const{
		if (pos < _size) {
			return _str[pos];
		}
	}

	size_t size() const {
		return _size;
	}

	//尾插入一个字符串
	void Append(const char* str) {
		//	int len = strlen(str);
		检查容量
		//	if (_size+len > _capacity) {
		//		reserve(_size + len);
		//	}
		尾插
		//	strcpy(_str + _size, str);
		修改size
		//	_size += len;
		insert(_size, str);
	}
	
	//+=运算符 (应用概率很高)
	String& operator+=(const char& ch) {
		pushBack(ch);
		return *this;
	}
   //+= 字符
	String& operator+=(const char* str) {
		Append(str);
		return *this;
	}
   //在pos位置的前面插入一个字符
	void insert(size_t pos, const char& ch) {
		if (pos > _size)
			return;
		//检查容量
		if (_size == _capacity) {
			size_t newC = _capacity == 0 ? 15 : 2 * _capacity;
			reserve(newC);
		}
		//移动元素[pos._size]:从后向前移动,先移动最右端,防止覆盖
		size_t end = _size + 1;
		while (end > pos) {
			//end >= pos  :当pos=0死循环,越界
			_str[end] = _str[end - 1]; //先移动的是'\0'
			--end;
		}
		//插入
		_str[pos] = ch;
		++_size;

	}
	//在pos位置的前面插入一个字符串
	void insert(size_t pos, const char* str) {
		if (pos > _size)
			return;
		int len = strlen(str);

		if (_size + len > _capacity) {
			reserve(_size + len);
		}
		//移动元素[pos,_size]  //移动的长度是字符串的长度
		size_t end = _size + len;
		while (end > pos + len - 1) {
			//第一次: size--->size+len 最后一次: pos--->pos+len
			_str[end] = _str[end - len];
			--end;
		}
		//插入: //每一个元素都要插入
		for (int i = 0; i < len; i++) {
			_str[i + pos] = str[i];
		}
		_size += len;
	}
	//扩充容量
	void resize(size_t n, const  char& ch = '\0') {
		if (n>_capacity) {
			reserve(n);
		}
		if (n > _size) {
			memset(_str + _size, ch, n - _size);
		}
		_size = n;
		_str[_size] = '\0';
	}
	//执行删除操作
	void erase(size_t pos, size_t len) {
		if (pos < _size) {
			//判断删除的长度是否大于从pos位置开始剩余的字符串的长度
			if (pos + len >= _size) {
				_size = pos;
				_str[_size] = '\0';
			}
			else {
				//移动元素:从前向后进行移动[pos+len,size]--->[pos,pos+size-len]
				//for (int i = pos + len; i <= _size; i++) {
					//_str[pos++] = _str[i];
				//}
				//_size -= len;
			//}
			size_t start = pos + len;
			while (start < _size) {

				_ptr[pos++] = _ptr[start];
				++start;
				/*_ptr[start - len] = _ptr[start];
				++start;*/

			}
			_size -= len;
			_ptr[_size] = '\0';
		}
	}

	size_t find(const char* str,size_t pos = 0) {
		char* ptr = strstr(_str, str);
		if (ptr) {
			return ptr - _str;
		}
		else {
			return npos;
		}
	}
//查找字符  
	size_t find(const char& ch, size_t pos = 0) {
		for (int i = pos; i < _size; i++) {
			if (_ptr[i] == ch)
				return i;
		}
		return npos;
	
	}


	void popback() {
		erase(_size - 1, 1);
	}
private:
	char* _str;
	size_t _size;
	size_t _capacity;
public:
	static const size_t npos;
};
//静态成员初始化
const size_t String::npos = -1;
String operator+(const String& s, const String& str) {
	String ret(s); //s的值是不变的,因此先拷贝一份
	ret += str.c_str();
	return ret;
}

String operator+(const String& s, const char* str) {

	String ret(s);
	ret += str;
	return ret;
}

String operator+(const String& s, const char ch) {
	String ret(s);
	ret += ch;
	return ret;
}
//输出运算符重载
ostream& operator<<(ostream& cout, const String& str) {

	//cout << str.c_str();
	//输出字符个数为size,不能遇到\0就结束
	//1.范围for
	/*for (const auto& ch : str) {
	cout << ch;
	}*/
	//2.operator[]
	/*for (int i = 0; i < str.size(); i++) {
	cout << str[i];
	}*/
	//3.迭代器
	String::const_iterator it = str.begin();
	while (it != str.end()) {
		cout << *it;
		++it;
	}
	return cout;
}

void test() {
	string s;
	const char* ptr = s.c_str();
	cout << s.c_str() << "结束" << endl;

	String Str;
	const char* ptr2 = Str.c_str();
	cout << Str.c_str() << "结束" << endl; //字符串打印 不不是打印的是指针,而是打印字符内容 /Str.c_str() 指针为空


	String str2("123");//常量位于代码段   位于常量区的不能直接使用delete进行释放,必须要将其进行拷贝然后在释放
	ptr2 = str2.c_str();
	cout << ptr2 << endl;
}
void  test2() {
	//因此在这块要进行重新写,拷贝构造
	String s("123");
	//调用拷贝构造
	String copy = s; //字节序拷贝:只拷贝成员变量,不拷贝资源
	String copy2(s);  //字节序拷贝   类似于s被多次释放的问题,

	//赋值运算符  要在上面重新写,假如不重新写那么释放会被释放两次
	String s2("456");
	copy = s2;
}
//字节序拷贝:只拷贝成员变量,不拷贝资源
//问题: 资源会被多次释放,程序崩溃
//必须要进行深拷贝的过程

void PrintString(const String& str) {
	//迭代器遍历
	String::const_iterator it = str.begin();
	while (it != str.end()) {
		cout << *it << " ";
		//写操作
		//*it = '0';
		++it;
	}
	cout << endl;
}
void test3() {
	String s = " ";
	s.pushBack('a');
	s.pushBack('b');
	s.pushBack('c');
	s.pushBack('d');
	s.pushBack('e');
	s.pushBack('f');
	s.pushBack('g');
	cout << s.c_str() << endl;
	//迭代器遍历
	String::iterator it = s.begin();
	while (it != s.end()) {
		cout << *it << " ";
		//写操作
		*it = '0';
		++it;
	}
	cout << endl;

	PrintString(s);
	cout << "范围for" << endl;
	//范围for:用引用接收可以进行修改
	for (char& ch : s) {
		cout << ch << " ";
		ch = '1';
	}
	cout << endl;
	for (char& ch : s) {  //这块使用引用可以进行读写操作
		cout << ch << " ";
		ch = '2';
	}
	cout << endl;
	for (char& ch : s) {
		cout << ch << " ";
	}
	cout << endl;
	cout << "范围for没有接收使用应用" << endl;
	for (char ch : s) { //没有使用引用类型
		cout << ch << " ";
		ch = '3';
	}
	cout << endl;
	for (char ch : s) { //没有使用引用类型
		cout << ch << " ";
		ch = '4';
	}
	cout << endl;

	//operator[]
	cout << "operator[]" << endl;
	for (int i = 0; i < s.size(); i++) {
		cout << s[i] << " ";
		//写操作
		s[i] = '7';
	}
	cout << endl;
	cout << "operator[]修改之后" << endl;
	for (int i = 0; i < s.size(); i++) {
		cout << s[i] << " ";
	}
	cout << endl;

}
void test4() {
	String s;
	//s.Append("12345");
	s += "12345";
	PrintString(s); //按照迭代器的方式来打印
	//s.Append("gfdsjhkfflsd");
	s += "6";
	s += "fdgasjhkg";
	PrintString(s);
}
void test5() {
	String s;
	s += "012345";
	s.insert(1, 'a');//0a12345
	s.insert(7, '6'); //0a123456
	s.insert(0, '9'); //90a123456
	PrintString(s);

	s.insert(3, "cdef");
	PrintString(s);
}
void test6() {
	String s("01234");
	PrintString(s);
	s.resize(3, 'a');
	PrintString(s);
	s.resize(6, 'a');//内容填充
	PrintString(s);
}

void test7() {
	String s("0123456789");
	PrintString(s);

	s.erase(3, 4); // 012789 从第三个位置开始,删除4个元素 
	PrintString(s); // 012789 从第三个位置开始,删除4个元素 

	s.erase(4, 2); //0127 从第四个位置开始,删除两个元素
	PrintString(s);//0127

	s.erase(2, 100);
	PrintString(s); //01
}


void test8() {
	String s("0123456789");
	size_t pos = s.find("789");

	pos = s.find("0123456789");
	if (pos == String::npos) {
		cout << "notfind" << endl;
	}
}

void test9() {
	//自定义的
	String s("0123");
	cout << s << endl;
	s.resize(10);
	cout << s << "结束" << endl;

	//库里的输出
	string s1("0123");
	cout << s1 << endl;
	s1.resize(10);
	cout << s1 << "结束" << endl;
}

void test10() {
	String s1("0123");
	String s2("456");
	String s3 = s1 + s2;
	String s4 = s1 + "789";
	String s5 = s1 + 'a';
	cout << s1 << endl;
	cout << s2 << endl;
	cout << s3 << endl;
	cout << s4 << endl;
	cout << s5 << endl;
}

int main() {
	//test();
	//test2();
	//test3();
	//test4();
	//test5();
	//test6();
	//test7();
	//test8();
	//test9();
	test10();
	system("color A");
	system("pause");
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值