196-C++运算符的重载(C++ string类的实现 & String迭代器的实现)

1、C++ string类的实现

1.1、“+”运算符重载函数

“+”运算符重载函数 其他函数要复杂一点!
在这里插入图片描述
这个写法的效率不好。

  • ptmp指向new出来的内存,然后字符串拷贝,连接,当做参数传入tmp对象,tmp构造的时候又会根据传进来的指针进行判空,然后开辟内存,进行字符串拷贝,然后把这个ptmp指针delete掉,tmp是局部对象,return tmp,析构的时候又要把刚才构造时new出来的空间delete掉,2次new2次delete,太麻烦了。

我们应该这么做:

String operator+(const String& lhs, const String& rhs)
{
	//char *ptmp = new char[strlen(lhs._pstr) + strlen(rhs._pstr) + 1];
	String tmp;
	tmp._pstr = new char[strlen(lhs._pstr) + strlen(rhs._pstr) + 1];
	strcpy(tmp._pstr, lhs._pstr);//拷贝函数 
	strcat(tmp._pstr, rhs._pstr);//连接函数 
	//delete[]ptmp;
	return tmp;
}

这样就比刚才少了1次的new和delete操作。
但是是临时对象,还是要进行大量的拷贝构造,优化的方法是调用右值引用构造

1.2、string类其他函数

过于简单,直接写在后面的源码中!

2、string字符串对象的迭代器iterator实现

迭代器是容器类型的嵌套类。

我们假设有一个string对象,里面有一堆字符串,这些内容我们是看不见,因为是私有的。
在这里插入图片描述
我们想迭代string对象底层的字符串的字符,用迭代器是怎么做到的?

  • 容器有一个begin方法,返回的是底层首元素的迭代器。
  • it指向了字符串底层的首元素。
  • 容器的end方法,返回的是最后一个元素的后继位置的迭代器。

在这里插入图片描述

  • 我们不用关心容器内部使用 数组/链表/红黑树…哪种数据结构存储的;也不用假设内存谁大谁小;
  • 我们只需要不断的遍历,遍历到最后一个元素,往后再走,遇到end()迭代器,就退出;
  • ++it,就是从当前元素跳到下一个元素去遍历。不需要管底层的数据结构。我们作为使用者只需要用迭代器++,不同的数据结构的差异都封装在迭代器++的重载运算符函数里面;
  • 对迭代器解引用,就是访问迭代器访问的底层的数据。

在这里插入图片描述
不同容器底层的数据结构不一样,每一种容器都有自己的迭代器,设置成嵌套类型。
在这里插入图片描述
迭代器用的都是前置++,因为返回的是*this,效率比较高,不用生成临时对象。

类比之前写的复数类!!!
在这里插入图片描述

**迭代器的功能:**提供一种统一的方式,来透明的遍历容器,我们不需要知道底层的数据结构,都封装在迭代器的++操作里面

#include <iostream>
#include <string>
//char arr[]="jkhsdkf";
using namespace std;

//自己实现一个字符串对象
class String
{
public:
	String(const char* p = nullptr)//构造函数 
	{
		if (p != nullptr)
		{
			_pstr = new char[strlen(p) + 1];
			strcpy(_pstr, p);
		}
		else
		{
			_pstr = new char[1];
			*_pstr = '\0';
		}
	}
	~String()//析构函数 
	{
		delete[]_pstr;
		_pstr = nullptr;
	}
	String(const String& str)//拷贝构造函数 
	{
		_pstr = new char[strlen(str._pstr) + 1];
		strcpy(_pstr, str._pstr);
	}
	String& operator=(const String& str)//赋值函数 
	{
		if (this == &str)
			return *this;

		delete[]_pstr;

		_pstr = new char[strlen(str._pstr) + 1];
		strcpy(_pstr, str._pstr);
		return *this;
	}
	bool operator>(const String& str)const
	{
		return strcmp(_pstr, str._pstr) > 0;
	}
	bool operator<(const String& str)const
	{
		return strcmp(_pstr, str._pstr) < 0;
	}
	bool operator==(const String& str)const
	{
		return strcmp(_pstr, str._pstr) == 0;
	}

	int length()const { return strlen(_pstr); }
	const char* c_str()const { return _pstr; }

	//char ch = str6[6];  可以修改:str6[6] = '7'
	char& operator[](int index) { return _pstr[index]; }
	//char ch = str6[6];  不允许修改!str6[6] = '7'
	const char& operator[](int index)const { return _pstr[index]; }

	//给String字符串类型提供迭代器的实现
	class iterator
	{
	public:
		iterator(char* p = nullptr) :_p(p) {}
		bool operator!=(const iterator& it)
		{
			return _p != it._p;
		}
		void operator++()
		{
			++_p;
		}
		char& operator*() { return *_p; }
	private:
		char* _p;
	};

	//下面2个方法是容器的方法哦!!! 
	//begin返回的是容器底层首元素的迭代器的表示
	iterator begin() { return iterator(_pstr); }
	//end返回的是容器末尾元素后继位置的迭代器的表示
	iterator end() { return iterator(_pstr + length()); }
private:
	char* _pstr;

	friend String operator+(const String& lhs, const String& rhs);
	friend ostream& operator<<(ostream& out, const String& str);
};

String operator+(const String& lhs, const String& rhs)
{
	//char *ptmp = new char[strlen(lhs._pstr) + strlen(rhs._pstr) + 1];
	String tmp;
	tmp._pstr = new char[strlen(lhs._pstr) + strlen(rhs._pstr) + 1];
	strcpy(tmp._pstr, lhs._pstr);//拷贝函数 
	strcat(tmp._pstr, rhs._pstr);//连接函数 
	//delete[]ptmp;
	return tmp;
}
ostream& operator<<(ostream& out, const String& str)
{
	out << str._pstr;
	return out;
}
int main()
{
	//迭代器的功能:提供一种统一的方式,来透明的遍历容器
	String str1 = "hello world!";//str1叫容器吗?叫。因为底层放了一组char类型的字符
	//容器的迭代器类型
	auto it = str1.begin();
	for (; it != str1.end(); ++it)
	{
		cout << *it << " ";
	}
	cout << endl;

	//c++11 foreach的方式来遍历容器的内部元素的值=>底层,还是通过迭代器进行遍历的
	for (char ch : str1)
	{
		cout << ch << " ";
	}
	cout << endl;

	//vector allocator  提供迭代器iterator的实现

	String str1;
	String str2 = "aaa";//string(const char*)
	String str3 = "bbb";
	String str4 = str2 + str3;
	String str5 = str2 + "ccc";
	String str6 = "ddd" + str2;

	cout << "str6:" << str6 << endl;
	//bool operator>(const String &str)
	if (str5 > str6)
	{
		cout << str5 << " > " << str6 << endl;
	}
	else
	{
		cout << str5 << " < " << str6 << endl;
	}

	int len = str6.length();
	for (int i = 0; i < len; ++i)
	{
		//char& str6.operator[](i)
		cout << str6[i] << " ";
	}
	cout << endl;

	//string -> char*
	char buf[1024] = { 0 };
	strcpy(buf, str6.c_str());//c_str()把对象管理的字符串返回成const char*类型 
	cout << "buf:" << buf << endl;

	return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

liufeng2023

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值