【C++】:string类基本接口的模拟实现

发布于:2024-05-18 ⋅ 阅读:(105) ⋅ 点赞:(0)

引言

上一篇文章已经对string类进行了简单的介绍,大家只要能够正常使用即可。

这篇文章主要是对string类的几个重点的基本接口函数进行模拟实现,分别有string类的构造,拷贝构造,赋值运算符重载,析构函数,以及交换函数。而这几个函数的模拟也有可能出现在面试中。

一,传统写法

//定义一个叫做bit的命名空间,隔离C++库里的string类
 namespace bit
{
	 class string
	 {
	 public:
	    //有参与无参构造用全缺省进行合并,在声明处给缺省值
		 string(const char* str = "")//传参构造
		 	:_size(strlen(str))
	     {
			//为了避免多次strlen计算,并且符合声明的顺序
			//只把_size放在初始化列表,其余放在函数体中
		
			_str = new char[_size + 1];//多开一个是给\0的
			_capacity = _size;
			strcpy(_str, str);//把初始化内容拷贝进空间
	     }

		//要用深拷贝进行拷贝构造
		//s2(s1);把s1拷贝给s2,*this是s2,s是s1的别名
		 string(const string& s)
		 {
		 	//开一个和要拷贝的一样大小的空间
			_str = new char[s._capacity + 1];
			strcpy(_str, s._str);//把数据拷贝进新空间
			_size = s._size;
			_capacity = s._capacity;
		 }

		 //赋值运算重载
		 //s1 = s3;//s1是*this,s是s3的别名
		 string& operator=(const string& s)
		 {
			//避免自己给自己赋值
			if (this != &s)
			{
				//开新空间,拷贝数据,释放原空间,改变指针指向
				char* tmp = new char[s._capacity + 1];
				strcpy(tmp, s._str);
				delete[] _str;
				_str = tmp;
				_size = s._size;
				_capacity = s._capacity;
		
				return *this;
			}
		 }

		 const char* c_str() const
		 {
			return _str;//返回字符串的首地址,用于打印数据
		 }

		 //交换函数
		 //s1.swap(s3)
		 //注意:这里传参要传引用,避免传值传参发生拷贝构造,语法上造成无穷递归
		 void swap(string& s)
		 {
			//调用库中的swap函数,交换内置类型
			//不直接交换数据,而是交换两块空间的指针
			std::swap(_str, s._str);
			std::swap(_size, s._size);
			std::swap(_capacity, s._capacity);
		 }

		 ~string()
		 {
			delete[] _str;//析构销毁资源
			_str = nullptr;//置空
			_size = _capacity = 0;//置0
		 }

	 private:
		 char* _str;
		 size_t _size;//有效数据个数,指向最后一个有效数据的下一个位置\0
		 size_t _capacity;//容量
	 };
}

二,现代写法

现代写法上的差异主要是拷贝构造,赋值拷贝发生了变化在这里效率上并没有提高多少,但是这种写法不仅适用于string类,后面的链表,树也同样适用。因为链表,树等要拷贝节点,不容易进行深拷贝。

namespace bit
{
	class string
	{
	public:
		//构造函数
		string(const char* str)
			:_size(strlen(str))
		{
			_str = new char[_size + 1];
			_capacity = _size;
			strcpy(_str, str);
		}
	
		//拷贝构造
		//s2(s1)
		//s是s1,*this是s2
		string(const string& s)
		{
			//复用构造函数,构造一个tmp,再用tmp对象和this交换
			//如果不在声明时给缺省值,刚开始s2是随机值,tmp和s2交换后
			//tmp就是随机值,tmp出了函数会调用析构函数,此时程序可能会崩溃
			//所以最好给缺省值
			string tmp(s._str);
			
			//显式调用swap函数
			//this->swap(tmp);
			swap(tmp);
		}
	
		//赋值运算符重载
		//s3 = s1
		//s1是s,s3是*this
		/*string& operator=(const string& s)
		{
			if (this != &s)
			{
				string tmp(s._str);
				swap(tmp);
			}
	
			return *this;
		}*/
	
		//s3 = s1   这里的传参不能用引用
		//传值传参会进行拷贝构造,s1会拷贝一份给tmp
		//再让tmp与s3交换
		string& operator=(string tmp)
		{
			swap(tmp);//一行代码实现赋值重载
	
			return *this;
		}
	
		const char* c_str()const
		{
			return _str;
		}
	
		void swap(string& s)
		{
			std::swap(_str, s._str);
			std::swap(_size, s._size);
			std::swap(_capacity, s._capacity);
		}
	
		//析构函数
		~string()
		{
			delete[] _str;
			_str = nullptr;
			_size = _capacity = 0;
		}
	
	private:
		char* _str = nullptr;
		size_t _size = 0;
		size_t _capacity = 0;
	};
}