string的实现

一般来说,为了防止与标准库中的string冲突,我们都会开一个命名空间。

构造函数,如果用最基本的构造函数,会怎么样

	class string 
	{
	public:
		string()
		:_str(nullptr)
		{}
		string(char* s)
		:_str(s)
		{
		}

这样子初始化的常量字符串,不能被修改,被存放再代码段,且扩容也不好处理。因此构造时候,不能直接传,要用new来动态开辟空间储存,因此其实string的底层是数组。

	string(const char* s = "")
		:_str(new char[strlen(s) + 1])
	{
		strcpy(_str, s);
	}
	

而析构则使用相对应的函数

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

当无参数时候,是空字符串,这样strlen就会为0,不然如果是空指针,则会出现空指针的解引用。

拷贝构造:
因为底层是一个字符指针,所以指针的拷贝,不能用浅拷贝,需用深拷贝。

string(const string& s)
			:_str(new char [strlen(s._str)+1]) 
		{
			strcpy(_str,s._str);
		}

这里便是深拷贝的写法,这里,主要利用的是,在类域中,可以直接访问对象的私有变量,即拷贝构造函数中,可以直接访问另一个引用同类对象的私有成员。

同样的operator=也需要深拷贝。

string& operator=(const string& s)
	{
		if (&s != this)
		{
			char* tmp = new char[strlen(s._str) + 1];
			strcpy(tmp, s._str);
			delete[] _str;
			_str = tmp;
		}

		return *this;
	}

而深拷贝也具有现代写法,是先构造一个相同对象,然后交换,宛如狸猫换太子。

string(const string& s)
			:_str(nullptr)
		{
			string tmp(s._str);
			swap(_str,_tmp._str);
		}
		
		string& operator=(string s)
		{
			swap(_str,s._str);
			return *this;
		}

赋值的现代写法,巧妙利用拷贝构造,直接换指针,这样不会影响原来的对象,因为那是形参。

当然这只是简单的string,只是实现了,基础的默认成员函数。

namespace whc
{
class string
{
public:

	typedef char* iterator;

	iterator begin()
	{
		return _str;
	}

	iterator end()
	{
		return _str + _size;
	}

	string(const char* s = "")
		:_str(new char[strlen(s) + 1])//因为有\0占一个位置
		,_size(strlen(s))
		,_capacity(strlen(s))
	{
		strcpy(_str, s);
	}
	
	~string()
	{
		_size = _capacity = 0;
		delete[] _str;
		_str = nullptr;
	}

	string(const string& s)
		:_str(new char[strlen(s._str)+1])
		,_size(s._size)
		,_capacity(s._capacity)
	{
		strcpy(_str, s._str);
	}

	string& operator=(const string& s)
	{
		_size = s._size;
		_capacity = s._capacity;

		if (&s != this)
		{
			char* tmp = new char[s._capacity + 1];
			strcpy(tmp, s._str);
			delete[] _str;
			_str = tmp;
		}

		return *this;
	}

	size_t size() const
	{
		return _size;
	}

	size_t capacity() const
	{
		return _capacity;
	}

	char operator[](size_t i) const
	{
		assert(i < _size);
		return _str[i];
	}

	const char* c_str() const
	{
		return _str;
	}

	void reserve(size_t n)
	{
		if (n > _capacity)
		{
			char* newcapa = new char[n + 1];
			strcpy(newcapa, _str);
			delete[] _str;
			_str = newcapa;
			_capacity = n;
		}
	}

	void rsize(size_t n, char ch = '\0')
	{
		if (n < _size)
		{
			_str[n] = '\0';
			_size = n;
		}
		else
		{
			if (n > _capacity)
			{
				reserve(n);
			}

			for (size_t i = _size; i < n; i++)
			{
				_str[i] = ch;
			}
			_size = n;
			_str[_size] = '\0';
		}
	}

	//这里也可以和insert复用
	void push_back(const char ch)
	{
		if (_size == _capacity)
		{
			size_t newcapacity = _capacity == 0 ? 2 : _capacity * 2;
			reserve(newcapacity);
		}

		_str[_size] = ch;
		_size++;
		_str[_size] = '\0';
	}

	//这里也可以和insert复用
	void append(const char* s)
	{
		size_t len = strlen(s);
		if (_size + len > _capacity)
		{
			reserve(_size + len);
		}

		strcpy(_str + _size, s);
		_size += len;
	}

	void append(const string& s)
	{
		size_t len = s.size();
		if (_size + len > _capacity)
		{
			reserve(_size + len);
		}

		strcpy(_str + _size, s._str);
		_size += len;
	}

	string& operator+=(const char ch)
	{
		push_back(ch);

		return *this;
	}

	string& operator+=(const char* s)
	{
		append(s);

		return *this;
	}

	string& operator+=(const string& s)
	{
		append(s);
		return *this;
	}

	string& insert(size_t pos, char ch)
	{
		assert(pos < _size);
		if (_size == _capacity)
		{
			size_t newcapa = _capacity == 0 ? 2 : _capacity * 2;
			reserve(newcapa);
		}

		int end = _size;
		while (end >= (int)pos)
		{
			_str[end + 1] = _str[end];
			end--;
		}
		_str[pos] = ch;
		_size++;

		return *this;
	}

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

		size_t len = strlen(s);
		if (_size + len > _capacity)
		{
			reserve(_size + len);
		}

		int end = _size;

		while (end >=(int)pos)//如果int小于0则与无符号比较会变成无符号。
		{
			_str[end + len] = _str[end];
			end--;
		}

		//第一种方式
		/*for (size_t i = 0; i < len; i++)
		{
			_str[pos++] = s[i];
		}*/

		//第二种方式
		strncpy(_str + pos, s, len);

		_size += len;

		return *this;
	}

	string& erase(size_t pos, size_t len = npos)
	{
		assert(pos < _size);
		if (len >= _size - pos)
		{
			_str[pos] = '\0';
			_size = pos;
		}
		else
		{
			size_t i = pos + len;
			while (i <= _size)
			{
				_str[pos++] = _str[i++];
			}

			_size -= len;
		}

		return *this;
	}

	size_t find(char ch , size_t pos = 0)
	{
		for (size_t i = pos; i < _size; i++)
		{
			if (_str[i] == ch)
			{
				return i;
			}
		}

		return npos;
	}

	size_t find(const char* s, size_t pos = 0)
	{
		char* p = strstr(_str, s);

		if (p == nullptr)
		{
			return npos;
		}

		return p - _str;
	}

	bool operator==(const string& s)
	{
		if (strcmp(_str, s._str) == 0)
		{
			return true;
		}

		return false;
	}

	bool operator<(const string& s)
	{
		if (strcmp(_str, s._str) < 0)
			return true;
		return false;
	}

	bool operator<=(const string& s)
	{
		return *this < s || *this == s;
	}

	bool operator>(const string& s)
	{
		return !(*this <= s);
	}

	bool operator>=(const string& s)
	{
		return !(*this < s);
	}

	bool operator!=(const string& s)
	{
		return !(*this == s);
	}

private:
	char* _str;
	size_t _size;
	size_t _capacity;
	static size_t npos;
};

size_t string:: npos = -1;

ostream& operator<<(ostream& out, string& s)
{
	for (size_t i = 0; i < s.size(); i++)
	{
		out << s[i];
	}

	return out;
}

istream& operator>>(istream& in, string& s)
{
	while (1)
	{
		char ch;
		ch = in.get();

		if (ch == ' ' || ch == '\n')
		{
			break;
		}
		else
		{
			s += ch;
		}

	}

	return in;
}

void test()
{
	string s("hello");
	string s1;
	string s2(s);
	string s3 = s;
	string s4("world");

	
	
	cin >> s1;
	cout << s1 << endl;
}

}

以上则是相对完整的string实现,这里我们也可以进一步理解迭代器,string的迭代器是一个指针,利用指针进行遍历,而范围for则是依赖迭代器而形成的。

这里还有深拷贝现代写法的完整形式。

	string(const string& s)
		:_str(nullptr)
		,_size(0)
		,_capacity(0)
	{
		string tmp(s._str);
		swap(tmp);
	}
	
	string& operator=(string s)
	{
		swap(s);
		return *this;
	}
	
	void swap(string& s)
	{
		::swap(_str,s._str);
		::swap(_size,s._size);
		::swap(_capacity,s._capacity);
	}

因为swap函数其作用域中,所以加域作用符来表明引用的是全局域的swap函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值