C++ string类底层模拟实现

目录

 

一、string介绍

二、string类底层模拟实现

1,默认成员函数的实现

a,构造函数

b, 析构函数

c,拷贝构造函数 

d,赋值运算符重载 

2,常用接口实现 

a,Iterator

b,Capacity

 c,Element access

d,Modifiers

e,String operations

f,Non-member function overloads

总代码:


一、string介绍

C语言中,字符串是以 ‘\0’ 结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数与字符串是分离开的,而且底层空间需要用户自己管理,稍不留神可能还会越界访问。

C++封装了这些接口和操作,创建出string类:

            1,string底层实际是:basic_string模板类的别名,typedef basic_string<char, char_traits, allocator>string

            2,string是表示字符串的字符串类

            3,该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作
   
            4,不能操作多字节或者变长字符的序列 

 

二、string类底层模拟实现

C++标准库中的string我们使用起来很方便,但我们只有自己去实现过string类的常用接口,我们才能更加深入的去了解string类。这里我将以多文件的形式去模拟实现string类,以下是我要实现的接口:

#ifndef _STRING_H_
#define _STRING_H_

#include <iostream>
#include <string>
#include <assert.h>
#pragma warning(disable:4996)
using namespace std;

namespace jzh
{
	class string
	{
	public:
		//构造函数
		string(const char* s = "")
		{
			if (nullptr == s)
				s = "";

			_size = strlen(s);
			_capacity = _size;
			_str = new char[_capacity + 1];
			strcpy(_str, s);
		}
		//拷贝构造函数
		string(const string& str)
			:_str(nullptr)
		{
			string tmp(str._str);
			swap(tmp);
		}
		//析构函数
		~string()
		{
			if (_str)
			{
				delete[] _str;
				_str = nullptr;
				_size = _capacity = 0;
			}
		}
		//赋值运算符重载
		string& operator=(const string& str)
		{
			if (this != &str)
			{
				string tmp(str);
				swap(tmp);
			}
			return *this;
		}

		//迭代器(iterator)
		typedef char* iterator;
		iterator begin();
		iterator end();
		
		typedef const char* const_iterator;
		const_iterator begin()const;
		const_iterator end()const;

		//容量(capacity)
		size_t size()const;
		size_t capacity()const;
		void reserve(size_t n);
		void resize(size_t n, char ch = '\0');
		void clear();
		bool empty()const;

		//元素访问(element access)
		char& operator[](size_t pos);
		const char& operator[](size_t pos)const;

		//修改操作(modify)
		string& insert(size_t pos, char ch);
		string& insert(size_t pos, const char* s);
		void push_back(char ch);
		string& append(const char* s);
		string& operator+=(char ch);
		string& operator+=(const char* s);
		string& operator+=(const string& str);
		string& erase(size_t pos = 0, size_t len = npos);
		void swap(string& str);

		//字符串操作(String operations)
		const char* c_str()const;
		size_t find(char ch, size_t pos = 0)const;
		size_t find(const char* sub, size_t pos = 0)const;
	private:
		size_t _size;
		size_t _capacity;
		char* _str;
	public:
		static const size_t npos;
	};
	//非成员函数重载(Non-member function overloads)
	istream& operator>>(istream& in, string& str);
	ostream& operator<<(ostream& out, const string& str);
	string operator+(const string& str, char ch);
	string operator+(const string& str, const char* s);
	string operator+(const string& s1, const string& s2);
}

#endif

1,默认成员函数的实现

         由于string类中涉及到资源的管理,所以其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给出。一般情况都是按照深拷贝方式提供。

a,构造函数

		string(const char* s = "")
		{
			if (nullptr == s)
				s = "";

			_size = strlen(s);
			_capacity = _size;
			//开辟一个与传入的字符串的长度 + 1的空间 ,+1是保存 \0
			_str = new char[_capacity + 1];
			//将传入的字符串内容拷贝到当前类的内容中
			strcpy(_str, s);
		}

b, 析构函数

		~string()
		{
			if (_str)
			{
				delete[] _str;
				_str = nullptr;
			}
		}

c,拷贝构造函数 

通过构造函数和传进来的对象创建一个临时对象,再将该临时对象的成员变量与新对象的成员变量做交换,从而完成拷贝构造。_str一开始要置为nullptr原因是让交换后的临时变量不进行释放。

		string(const string& str)
			:_str(nullptr)
		{
			//复用构造函数创建临时对象
			string tmp(str._str);
			//swap的实现代码在后面
			swap(tmp);
		}

d,赋值运算符重载 

		string& operator=(const string& str)
		{
			if (this != &str)
			{
				string tmp(str);
				swap(tmp);
			}
			return *this;
		}

2,常用接口实现 

a,Iterator

jzh::string::iterator jzh::string::begin()
{
	return _str;
}
jzh::string::iterator jzh::string::end()
{
	return _str + _size;
}

//const类型
jzh::string::const_iterator jzh::string::begin()const
{
	return _str;
}
jzh::string::const_iterator jzh::string::end()const
{
	return _str + _size;
}

b,Capacity

size_t jzh::string::size()const
{
	return _size;
}

size_t jzh::string::capacity()const
{
	return _capacity;
}

void jzh::string::reserve(size_t n)
{
	if (n > _capacity)
	{
		char* tmp = new char[n + 1];
		strcpy(tmp, _str);

		delete[] _str;
		_str = tmp;
		_capacity = n;
	}
}

void jzh::string::resize(size_t n,char ch)
{
	if (n > _size)
	{
		if (n > _capacity)
		{
			reserve(n);
		}
		for (size_t i = _size; i < n; i++)
		{
			_str[i] = ch;
		}
	}
	_size = n;
	_str[n] = '\0';
}

void jzh::string::clear()
{
	_size = 0;
	_str[0] = '\0';
}

bool jzh::string::empty()const
{
	return 0 == _size;
}

 c,Element access

char& jzh::string::operator[](size_t pos)
{
	assert(pos < _size);

	return _str[pos];
}
const char& jzh::string::operator[](size_t pos)const
{
	assert(pos < _size);

	return _str[pos];
}

d,Modifiers

jzh::string& jzh::string::insert(size_t pos, char ch)
{
	assert(pos <= _size);

	if (_size == _capacity)
	{
		if (0 == _capacity)
			reserve(15);
		else
			reserve(_capacity * 2);
	}
	size_t end = _size + 1;
	while (end > pos)
	{
		_str[end] = _str[end - 1];
		end--;
	}
	_str[pos] = ch;
	_size++;

	return *this;
}

jzh::string& jzh::string::insert(size_t pos, const char* s)
{
	assert(pos <= _size);

	size_t len = strlen(s);
	if (len + _size > _capacity)
	{
		reserve(len + _size);
	}
	size_t end = _size + len;
	while (end != 0 && end >= pos + len)
	{
		_str[end] = _str[end - len];
		end--;
	}
	strncpy(_str + pos, s, len);
	_size += len;

	return *this;
}

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

jzh::string& jzh::string::append(const char* s)
{
	insert(_size, s);
	return *this;
}

jzh::string& jzh::string::operator+=(char ch)
{
	push_back(ch);
	return *this;
}
jzh::string& jzh::string::operator+=(const char* s)
{
	append(s);
	return *this;
}
jzh::string& jzh::string::operator+=(const string& str)
{
	append(str._str);
	return *this;
}

jzh::string& jzh::string::erase(size_t pos, size_t len)
{
	assert(pos < _size);

	if (len == npos || pos + len >= _size)
	{
		_str[pos] = '\0';
		_size = pos;
	}
	else
	{
		strcpy(_str + pos, _str + pos + len);
		_size -= len;
	}

	return *this;
}

void jzh::string::swap(string& str)
{
	std::swap(_str, str._str);
	std::swap(_size, str._size);
	std::swap(_capacity, str._capacity);
}

e,String operations

const char* jzh::string::c_str()const
{
	return _str;
}

size_t jzh::string::find(char ch, size_t pos)const
{
	assert(pos < _size);

	for (size_t i = pos; i < _size; i++)
	{
		if (ch == _str[i])
			return i;
	}
	return npos;
}

size_t jzh::string::find(const char* sub, size_t pos)const
{
	assert(pos < _size);

	const char* ret = strstr(_str + pos, sub);
	if (nullptr == ret)
		return npos;
	else
		return ret - _str;

}

f,Non-member function overloads

istream& jzh::operator>>(istream& in, string& str)
{
	str.resize(0);
	char ch = 'a';
	while (1)
	{
		in.get(ch);
		if (ch==' ' || ch == '\n')
		{
			break;
		}
		else
		{
			str += ch;
		}
	}
	return in;
}

ostream& jzh::operator<<(ostream& out, const string& str)
{
	for (size_t i = 0; i < str.size(); i++)
	{
		out << str[i];
	}
	return out;
}

string operator+(const string& str, char ch)
{
	string tmp(str);
	tmp += ch;
	return tmp;
}

string operator+(const string& str, const char* s)
{
	string tmp(str);
	tmp += s;
	return tmp;
}

jzh::string jzh::operator+(const string& s1, const string& s2)
{
	string tmp(s1);
	tmp += s2;
	return tmp;
}

总代码:

#include "string.h"

const size_t jzh::string::npos = -1;

//迭代器(Iterator)
jzh::string::iterator jzh::string::begin()
{
	return _str;
}
jzh::string::iterator jzh::string::end()
{
	return _str + _size;
}

jzh::string::const_iterator jzh::string::begin()const
{
	return _str;
}
jzh::string::const_iterator jzh::string::end()const
{
	return _str + _size;
}

//容量(capacity)
size_t jzh::string::size()const
{
	return _size;
}

size_t jzh::string::capacity()const
{
	return _capacity;
}

void jzh::string::reserve(size_t n)
{
	if (n > _capacity)
	{
		char* tmp = new char[n + 1];
		strcpy(tmp, _str);

		delete[] _str;
		_str = tmp;
		_capacity = n;
	}
}

void jzh::string::resize(size_t n,char ch)
{
	if (n > _size)
	{
		if (n > _capacity)
		{
			reserve(n);
		}
		for (size_t i = _size; i < n; i++)
		{
			_str[i] = ch;
		}
	}
	_size = n;
	_str[n] = '\0';
}

void jzh::string::clear()
{
	_size = 0;
	_str[0] = '\0';
}

bool jzh::string::empty()const
{
	return 0 == _size;
}

//元素访问(element access)
char& jzh::string::operator[](size_t pos)
{
	assert(pos < _size);

	return _str[pos];
}
const char& jzh::string::operator[](size_t pos)const
{
	assert(pos < _size);

	return _str[pos];
}

//修改操作(Modifiers)
jzh::string& jzh::string::insert(size_t pos, char ch)
{
	assert(pos <= _size);

	if (_size == _capacity)
	{
		if (0 == _capacity)
			reserve(15);
		else
			reserve(_capacity * 2);
	}
	size_t end = _size + 1;
	while (end > pos)
	{
		_str[end] = _str[end - 1];
		end--;
	}
	_str[pos] = ch;
	_size++;

	return *this;
}

jzh::string& jzh::string::insert(size_t pos, const char* s)
{
	assert(pos <= _size);

	size_t len = strlen(s);
	if (len + _size > _capacity)
	{
		reserve(len + _size);
	}
	size_t end = _size + len;
	while (end != 0 && end >= pos + len)
	{
		_str[end] = _str[end - len];
		end--;
	}
	strncpy(_str + pos, s, len);
	_size += len;

	return *this;
}

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

jzh::string& jzh::string::append(const char* s)
{
	insert(_size, s);
	return *this;
}

jzh::string& jzh::string::operator+=(char ch)
{
	push_back(ch);
	return *this;
}
jzh::string& jzh::string::operator+=(const char* s)
{
	append(s);
	return *this;
}
jzh::string& jzh::string::operator+=(const string& str)
{
	append(str._str);
	return *this;
}

jzh::string& jzh::string::erase(size_t pos, size_t len)
{
	assert(pos < _size);

	if (len == npos || pos + len >= _size)
	{
		_str[pos] = '\0';
		_size = pos;
	}
	else
	{
		strcpy(_str + pos, _str + pos + len);
		_size -= len;
	}

	return *this;
}

void jzh::string::swap(string& str)
{
	std::swap(_str, str._str);
	std::swap(_size, str._size);
	std::swap(_capacity, str._capacity);
}

//字符串操作(String operations)
const char* jzh::string::c_str()const
{
	return _str;
}

size_t jzh::string::find(char ch, size_t pos)const
{
	assert(pos < _size);

	for (size_t i = pos; i < _size; i++)
	{
		if (ch == _str[i])
			return i;
	}
	return npos;
}

size_t jzh::string::find(const char* sub, size_t pos)const
{
	assert(pos < _size);

	const char* ret = strstr(_str + pos, sub);
	if (nullptr == ret)
		return npos;
	else
		return ret - _str;

}

//非成员函数重载(Non-member function overloads)
istream& jzh::operator>>(istream& in, string& str)
{
	str.resize(0);
	char ch = 'a';
	while (1)
	{
		in.get(ch);
		if (ch==' ' || ch == '\n')
		{
			break;
		}
		else
		{
			str += ch;
		}
	}
	return in;
}

ostream& jzh::operator<<(ostream& out, const string& str)
{
	for (size_t i = 0; i < str.size(); i++)
	{
		out << str[i];
	}
	return out;
}

string operator+(const string& str, char ch)
{
	string tmp(str);
	tmp += ch;
	return tmp;
}

string operator+(const string& str, const char* s)
{
	string tmp(str);
	tmp += s;
	return tmp;
}

jzh::string jzh::operator+(const string& s1, const string& s2)
{
	string tmp(s1);
	tmp += s2;
	return tmp;
}

 

本文若有不足之处欢迎大家指出,谢谢大家!!

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值