Bootstrap

简单实现一下string类

自己简单实现一下String类,代码如下:

//自己简单实现一下String类
#pragma warning( disable : 4996)
class MyString
{
private:
	char*_data;
	size_t _len;
	void _init_data(const char*s)
	{
		_data = new char[_len + 1];
		memcpy(_data, s, _len);
		_data[_len] = '\0';
	}
public:
	MyString() :_data(NULL), _len(0) { }//default constructor
	MyString(const char*p) :_len(strlen(p))//constructor
	{
		_init_data(p);
		//cout << "constructor" << endl;
	}
	MyString(const MyString&str) :_len(str._len)//copy constructor
	{
		_init_data(str._data);
	}

	MyString&operator=(const MyString&str)//copy assignment
	{
		if (this != &str)
		{
			if (this->_data)delete[] _data;
			_len = str._len;
			this->_init_data(str._data);
		}
		else
		{
		}
		return *this;
	}

//C++11
	MyString(MyString&&str) noexcept:_data(str._data), _len(str._len)//move constructor 形参是右值引用
	{
		//noexcept关键字告诉编译器,函数中不会发生异常
		str._data = NULL;//避免浅拷贝
		str._len = 0;
	}

	MyString&operator=(MyString&&str)noexcept//move assignment
	{
		if (this != &str)
		{
			this->_data = str._data;
			str._data = NULL;
			this->_len = str._len;
			str._len = 0;
		}

		return *this;
	}

	~MyString()//destructor
	{
		delete[] this->_data;
	}

	char*get()const
	{
		return this->_data;
	}
	bool operator==(const MyString&rhs)const
	{
		return strcmp(this->_data, rhs._data) == 0 ? true : false;
	}
	bool operator<(const MyString&rhs)const
	{
		return strcmp(this->_data, rhs._data) < 0 ? true : false;
	}
	MyString operator+(const MyString&rhs)
	{
		MyString ret;
		ret._len = this->_len + rhs._len;
		ret._data = new char[ret._len + 1];
		strcpy(ret._data, this->_data);//回顾一下strcpy(dest,src)把从src地址开始且含有null结束符的字符串复制到以dest开始的地址空间
		strcat(ret._data, rhs._data);//回顾一下strcat(dest,src)把src所指的字符串添加到dest结尾处(覆盖结尾处的'\0')并添加'\0'
		return ret;

	}

	MyString&operator+=(const MyString&rhs)
	{
		if (rhs._data == NULL)
			return *this;
		if (this == &rhs)//如果出现了自己加自己的情况(必须判断这种情况)
		{
			MyString copy(*this);//调用copy constructor
			return *this += copy;//再次调用该函数本身,但是这一次调用不会进入if了
		}

		this->_len += rhs._len;
		char*p_old = this->_data;
		this->_data = new char[this->_len + 1];
		strcpy(this->_data, p_old);
		strcat(this->_data, rhs._data);

		delete[] p_old;
		return *this;

	}
	
    MyString&operator+=(const char&rhs)
	{
		this->_len += 1;
		char*p_old = this->_data;
		this->_data = new char[this->_len + 1];
		strcpy(this->_data, p_old);
		_data[this->_len - 1] = rhs;
		_data[this->_len] = '\0';

		delete[] p_old;
		return *this;

	}

	char& operator[](const size_t index)
	{
		if (index < 0 || index >= this->_len)
		{
			throw exception("越界啦");
		}
		return this->_data[index];
	}
	//ostream
	friend ostream& operator<< (ostream& out, const MyString &str)//友元函数
	//需要把运算符重载函数声明为类的友元函数,这样我们就能不用创建对象而直接调用函数
	{
		if (str._data != NULL)
		{
			out << str._data;
		}
		return out;
	}
	// istream
	friend istream& operator >> (istream& in, MyString& str)//友元函数
	{
		char tmp[100];// 临时字符串  
		if (in >> tmp)
		{
			delete[] str._data;
			str._len = strlen(tmp);
			str._data = new char[str._len + 1];
			strcpy(str._data, tmp);
		}
		return in;
	}


	//这里操作符重载只简单地写几个,其他就不写了,不难
	bool isEmpty()
	{
		return this->_len == 0 ? true : false;
	}
	size_t length()
	{
		return this->_len;
	}
	const char*c_str()//将C++的string转化为C的字符串,c_str()生成一个const char *指针
	{
		return this->_data;
	}
	MyString&append(const MyString&rhs)
	{
		*this += rhs;
		return *this;
	}

	MyString substr(size_t pos, const size_t n)//substr返回的是对象,不是引用//s.substr(pos, n)返回一个包含s中从pos开始的n个字符的拷贝
	{
		if ((pos + n) > this->_len)
			throw exception("越界啦");
		MyString ret;
		ret._len = n;
		ret._data = new char[ret._len + 1];
		for (size_t i = 0; i < n; i++)
		{
			ret._data[i] = this->_data[pos + i];//调用[]重载函数
		}
		ret._data[n] = '\0';
		return ret;
	}

	MyString&erase(size_t pos, size_t n)//erase(pos,n)删除从pos开始的n个字符
	{
		if (pos >= _len)
		{
			throw("越界啦");
		}
		if ((pos + n - 1) >= this->_len)//自动修正功能
		{
			n = _len - pos;
		}
		char*p_old = this->_data;
		this->_len -= n;//更新_len
		this->_data = new char[this->_len + 1];
		for (size_t i = 0; i < pos; i++)//p_old数组下标[0,pos-1]
		{
			this->_data[i] = p_old[i];
		}
		for (size_t i = pos; i < this->_len; i++)//p_old数组下标[pos+n,pos+_len-1]
		{
			this->_data[i] = p_old[n + i];
		}
		this->_data[this->_len] = '\0';
		delete[] p_old;
		return *this;
	}


	void swap(MyString&lhs, MyString&rhs)
	{
		lhs._len ^= rhs._len;
		rhs._len ^= lhs._len;
		lhs._len ^= rhs._len;

		char*temp = lhs._data;
		lhs._data = rhs._data;
		rhs._data = temp;

	}
};
int main()
{
	cout << sizeof(MyString) << endl;
	MyString str1("Chinese");
	cout << (str1.substr(1, 6)).get() << endl;
	cout << str1 << endl;
	str1 += "123";
	cout << str1.get() << endl;
	str1.append("456");
	cout << str1.get() << endl;
	str1.erase(7, 2);
	cout << str1 << endl;
	cin >> str1;
	cout << str1 << endl;
	cout << "---------------------------------------------------" << endl;
	MyString str2;
	str2 = str1;//断点copy assignment

	MyString str3(str1);//断点copy constructor

	MyString str4(move(str1));//断点move constructor
	cout << str1.length() << endl;//这里特别注意,使用move后str1被掏空,失效了,最好不要再去使用str1
	cout << "---------------------------------------------------" << endl;
	MyString str5;
	str5 = MyString("abc");//断点move assignment,因为返回的是一个右值

	MyString str6("xyz");
	MyString str7("lalala");
	cout << str7.get() << endl;
	str7 = str6.substr(0, 1);//断点move assignment,因为返回的是一个右值
	cout << str7.get() << endl;
	cout << "---------------------------------------------------" << endl;

	MyString str8 = MyString("aaa");//注意,这里只会调用1次constructor,除此以外不会调用其他任何函数
	//这是为什么呢,原因是编译器会自动进行优化,将上面这句话优化为MyString str8("aaa");
	system("pause");
	return 0;
}

在这里插入图片描述

;