0
点赞
收藏
分享

微信扫一扫

C++ 自定义String类

爱动漫建模 2022-02-22 阅读 61
c++

C++ 自定义String类


想要实现高级的String类还挺复杂的,C++和C#不一样,许多模块都需要自己来解决内存问题,并且如何提高内存空间的利用效率,调用函数是否触发拷贝构造函数,触发拷贝构造函数时又该如何避免重复的内存释放。

还剩下几个重载没实现,剩下明天再写,关于该类的测试和说明还需要慢慢补充。

类的声明

使用char来实现一个string类。
首先是定义一个String类,然后定义内部的成员变量和成员函数。
内容:
1.

私有成员说明
_str字符串
_size字符串长度
bool _SetString封装设置_str和_size
_log用于测试的临时输出信息,由于要节省时间,暂时使用string储存,类实现完毕后删除所有log相关代码
公有成员说明
String构造函数包括默认构造函数,重载字符数组,重载拷贝构造函数,以及实现move函数
~String析构函数,销毁对象时对内存进行释放
String& operator =重载=操作符,并实现move函数,难点在于写成了自身的递归
(暂未实现)String operator +重载+操作符,由于返回的是临时变量,前面应当加上const,并且函数头不需要使用引用
(暂未实现)String operator +=重载+=操作符,应该与重载=操作符类似
char& operator[]重载中括号,要实现c=s[0]和s[0]=c
(暂未实现)istream& operator >>重载输入流,需要研究一下有没有高效写法,以及会不会出现 \r\n 的问题
(暂未实现)ostream& operator <<重载输出流
String* GetAddress返回自身地址
String GetCopy()返回克隆
String& GetOriginal()返回本身
char* c_str()返回字符串本身的字符数组地址,要加上const防止被修改内存
int length()返回字符串长度
class String {
private:
	char* _str = NULL;
	size_t _size = 0;
	string _log;
	bool _SetString(const char* str);
public:
	String();
	String(const char *str);
	String(const String& other);
	String(String&& other) noexcept; // TODO: noexcept
	~String();

	// 重载 = 操作符
	String& operator =(const char* str);
	String& operator =(const String& other);
	String& operator =(String&& other) noexcept; // TODO: noexcept

	// 重载+操作符, 返回的是临时对象,不需要使用引用
	const String operator +(const char* str);
	const String operator +(const char ch);
	const String operator +(const String& other);

	// 重载+=操作符
	String operator +=(const char* str);
	String operator +=(const char ch);
	String operator +=(const String& other);

	// 重载中括号
	//char operator[](size_t index);
	char& operator[](size_t index); // 可以实现str[0]='1'

	// 重载==操作符
	bool operator ==(const char* str);
	bool operator ==(const String& other);

	// 重载输入输出流
	friend istream& operator >> (istream& cin, String& str);
	friend ostream& operator << (ostream& cin, String& str);

	//返回自身地址
	String* GetAddress() { return this; }
	// 返回克隆
	String GetCopy() { return *this; }
	// 返回本身
	String& GetOriginal() { return *this; }

	// 返回字符串本身的字符数组地址,加上const防止被修改
	const char* c_str() { return _str; }

	// 返回字符串长度
	int length() { return _size; }
};

_SetString

bool String::_SetString(const char* str)
{
	try {
		if (str == NULL) {
			_size = 0;
			_str = NULL;
		}
		else {
			if (_str != NULL) {
				delete[] _str;
				_str = NULL;
			}
			_size = strlen(str);
			_str = new char[_size + 1];
			strcpy(_str, str);
			_str[_size] = '\0';
		}
	}
	catch(...){
		return false;
	}
	return true;
}

构造函数和析构函数

String::String() {
	// 在声明处已经初始化了变量,该析构函数只是为了输出信息
	_log = "String()";
	cout << "String()" << endl;
}


String::String(const char* str)
{
	_SetString(str);
	_log = "String(const char* str)";
	cout << "String(const char* str)" << endl;
}

String::String(const String& other)
{
	_SetString(other._str);
	_log = "String(const String& s)";
	cout << "String(const String& s)" << endl;
}

// String的move实现
String::String(String&& other) noexcept
{
	_size = other._size;
	_str = other._str;
	other._size = 0;
	// 这样在析构other的时候,不会回收other._str指向的内存空间
	other._str = NULL;
}

String::~String()
{
	cout << "~String" << _log << endl;
	if (_str != NULL) {
		delete _str;
		_str = NULL;
	}
}

待测试项

String s1();
String s2("123");
String s3(s2);
String s4 = s2; // s4未被实例化,此处等价于String s4(s2)
String s5;
s5 = s2; // 触发=重载

如果没重载=,会报错“尝试引用已删除的函数”,因此必须重载
触发“尝试引用已删除的函数”的条件:

  • 含有非静态的const成员变量
  • 含有非静态的reference成员变量
  • 含有不能被拷贝的成员变量
  • 含有不能被拷贝的基类
  • 含有用户定义的移动构造函数或者移动赋值函数

看到其他博客对move的解释(暂时没看懂先用着):
std::move可以将一个左值引用强制转为右值引用,只是转移状态没有转移内存,等同于 static_cast<T&&>
而函数参数T&&是一个指向模板类型参数的右值引用,通过引用折叠,此参数可以与任何类型的实参匹配

重载=操作符

String& String::operator=(const char* str)
{
	cout << "operator=(const char* str)" << endl;
	_SetString(str);
	return *this;
}

String& String::operator=(const String& other)
{
	cout << "operator=(const String& other) self" << endl;
	// 检查自赋点
	if (this != &other) {
		// 释放内存,分配新空间

		_SetString(other._str);
	}
	return *this;
}

String& String::operator=(String&& other) noexcept
{
	cout << "operator=(String&& other)" << endl;
	// 检查自赋点
	if (this != &other) {
		_size = other._size;
		_str = other._str;
		other._size = 0;
		other._str = NULL;
	}
	return *this;
}

下面是错误写法,会进入无限递归的死循环,我很自然的以为*this=String(…)可以实现我想要的拷贝,但是会不断触发第三个拷贝而进入死循环

String& String::operator=(const char* str)
{
	cout << "operator=(const char* str)" << endl;
	*this = String(str);
	return *this;
}

String& String::operator=(const String& other)
{
	cout << "operator=(const String& other)" << endl;
	*this = String(other);
	return *this;
}

String& String::operator=(String&& other) noexcept
{
	cout << "operator=(String&& other)" << endl;
	*this = String(other);
	return *this;
}

待测试

String s("123");
String s2("456");
String *s3;
s3 = &s2; // 指针引用
String s4;
s4 = CreateString("111"); // 触发第三个=重载
cout << endl<< s[0] <<endl;
cout << endl<< s2[0] <<endl;
s[0]='9';
cout << endl << s[0] << endl;
cout << endl << s2[0] << endl;
cout << endl << (*s3)[0] << endl;

重载+操作符


重载+=操作符


重载中括号

char& String::operator[](size_t index)
{
	return _str[index];
}

重载==操作符


重载输入输出流


返回地址/克隆/自身


举报

相关推荐

0 条评论