运算符重载

复数类重载

#include<iostream>
using namespace std;

/*
	C++运算符重载:使对象的运算表现得和编译器内置类型一致
	模板代码,可以使得运算符执行类模板进行运算

	template<typename T>
	T sum(T a,T b)
	{
		return a+b;		//a+.(b) a.operator+(b)
	}

*/
//复数类
class CComplex
{
public:
	CComplex (int r=0, int i=0)
		:_real(r)
		, _vir(i)
	{

	}

	//指导编译器怎么做CComplex类对象的加法操作
	//不能返回对象的引用,首先两个+法操作的对象不能改变,局部对象的引用不能返回
	CComplex operator+(const CComplex& com)
	{
		//->堆上等地址使用 .对象本身使用
		/*CComplex<T> temp;
		temp._real = this->_real + com._real;
		temp._vir = this->_vir + com._vir;
		return temp;*/

		//优化 减少临时对象的构造和析构
		return CComplex(this->_real + com._real, this->_vir + com._vir);
	}

	//++ -- 单目运算符  
	//operator++()		前置++ 
	//operator++(int)	后置++

	CComplex& operator++()
	{
		_real += 1;
		_vir += 1;
		return *this;
	}

	CComplex operator++(int)
	{
		//局部对象,不能返回引用
		//CComplex comp = *this;
		//_real += 1;
		//_vir += 1;
		//return comp;
		return CComplex(_real++, _vir++);
	}
	//不需要返回值 参数不用改变
	void operator+=(const CComplex& src)
	{
		_real += src._real;
		_vir += src._vir;
	}
	void show()
	{
		cout << "this" << this << endl;
		cout << "real:" << _real << endl;
		cout << "vir:" << _vir << endl;
	}
private:
	int _real;
	int _vir;
	//友元函数,可以访问私有成员变量
	friend CComplex operator+ (const CComplex& lhs, const CComplex& rhs);
	friend	ostream& operator<<(ostream& out, const CComplex& src);3
	friend istream& operator>>(istream &in, CComplex &srx);
};

CComplex operator+ (const CComplex &lhs,const CComplex &rhs)
{
	return CComplex(lhs._real + rhs._real, lhs._vir + rhs._vir);
}

//cout ::operator << (cout,comp1) void << endl不可以,所以只能返回cout类型
ostream& operator<<(ostream& out, const CComplex& src)
{
	out << "_real" << src._real << "_vir" << src._vir << endl;
	return out;
}
istream& operator>>(istream &in, CComplex &srx)
{
	in >> src._real>>src._vir;
	return in;
}
int main()
{
	CComplex comp1(10, 10);
	CComplex comp2(20, 20);
	//comp1.operator+(comp2)			加法运算符的重载函数
	CComplex comp3 = comp1 + comp2;
	comp3.show();
	//编译器在类模板中寻找 带整型参数的构造函数 把整数转成CComplex类型(传入参数的用传入参数,没传入参数的用默认值) 形参类型强制转换
	CComplex comp4 = comp1 + 20;
	comp4.show();
	//30 无法调用运算符重载,没有任何理由去做类型转换,
	//编译器做对象运算的时候,会调用对象的运算符重载函数(优先调用成员方法,无成员方法就在全局作用域找合适的运算符重载函数)
	//全局函数 发生类型转换,没法调用成员方法
	CComplex comp5 = 30 + comp2;
	comp5.show();


	//后置++		operator++(int)
	comp5 = comp1++;
	comp5.show();
	comp1.show();
	//前置++		operator++()
	comp5 = ++comp1;
	comp5.show();
	comp1.show();
	//comp1.operator+=(comp2)	::operator+=(comp1,comp2)
	comp1 += comp2;
	comp1.show();

	
	return 0;
}


//模板打印碰见自定义类型,如何处理
template<typename T>
void show(T a)
{

	cout << a << endl;
}

模拟C++String类代码

#include<iostream>
#include<string>
using namespace std;

class String
{
public:
	String(const char* p = nullptr)
	{
		if (p != nullptr)
		{
			//strlen 只计算有效字符串的个数,不计算末尾'\0'所以要+1
			_pstr = new char[strlen(p) + 1];
			strcpy(_pstr, p);
		}
		else
		{
			_pstr = new char[1];
			*_pstr = '\0';
		}
	}
	
	~String()
	{
		delete[] _pstr;
		_pstr = nullptr;
	}

	String(const String& src)
	{
		_pstr = new char[strlen(src._pstr) + 1];
		strcpy(_pstr, src._pstr);
	}

	String& operator=(const String& src)
	{
		if (this == &src)
		{
			return *this;
		}

		delete[] _pstr;
		_pstr = new char[strlen(src._pstr) + 1];
		strcpy(_pstr, src._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;
	}
	//有效字符的个数,不包括'\0'
	int length()const
	{
		return strlen(_pstr);
	}
	//为了可以修改,返回引用,可以读可以改
	char& operator[](int index)
	{
		return _pstr[index];
	}
	//常对象,返回值不许修改,只读
	const char& operator[](int index)const
	{
		return _pstr[index];
	}
	const char* c_str()const
	{
		return _pstr;
	}
private:
	//String本质是对char* 指针的一个封装
	char* _pstr;
	friend String operator+(const String& lhs, const String& rhs);
	friend ostream& operator<<(ostream& out, const String& str);
};

//不delete会发生内存泄露,改后效率低下
/*
String operator+(const String& lhs,const String& rhs)
{
	char* ptmp = new char[strlen(lhs._pstr) + strlen(rhs._pstr) + 1];
	strcpy(ptmp, lhs._pstr);
	strcat(ptmp, rhs._pstr);
	String tmp(ptmp);
	delete[]ptmp;
	return tmp;
}
*/
String operator+(const String& lhs, const String& rhs)
{
	String tmp;
	tmp._pstr = new char[strlen(lhs._pstr) + strlen(rhs._pstr) + 1];
	strcpy(tmp._pstr, lhs._pstr);
	strcat(tmp._pstr, rhs._pstr);
	return tmp;

}

ostream& operator<<(ostream& out, const String& str)
{
	out << str._pstr;
	return out;
}
//char arr[] = "jkshshk"
int main()
{
	String str1;				//默认构造
	String str2 = "aaa";		//提供了const char*类型的构造函数
	String str3 = "bbb";		//
	String str4 = str2 + str3;
	String str5 = str2 + "ccc";	//默认类型转换构造后面字符串的对象
	String str6 = "ddd" + str2;	//不默认,需要构造全局函数,无法调用运算符重载,没有理由进行类型转换

	cout << "str6:" << str6 << endl;
	if (str5 > str6)
	{
		cout << str5 << " > " << str6 << endl;
	}
	else
	{
		cout << str5 << " < " << str6 << endl;
	}

	int len = str6.length();
	for (int i = 0; i < len; ++i)
	{
		//将对象当作数组名来使用,访问字符串底层指定序号的字符,提供了下标运算符重载函数
		cout << str6[i] << " ";
	}

	//string--->char*
	char buf[1024] = { 0 };
	strcpy(buf, str6.c_str());

	return 0;
}

对象迭代器iterator

String

#include<iostream>
#include<string>
using namespace std;

class String
{
public:
	String(const char* p = nullptr)
	{
		if (p != nullptr)
		{
			//strlen 只计算有效字符串的个数,不计算末尾'\0'所以要+1
			_pstr = new char[strlen(p) + 1];
			strcpy(_pstr, p);
		}
		else
		{
			_pstr = new char[1];
			*_pstr = '\0';
		}
	}

	~String()
	{
		delete[] _pstr;
		_pstr = nullptr;
	}

	String(const String& src)
	{
		_pstr = new char[strlen(src._pstr) + 1];
		strcpy(_pstr, src._pstr);
	}

	String& operator=(const String& src)
	{
		if (this == &src)
		{
			return *this;
		}

		delete[] _pstr;
		_pstr = new char[strlen(src._pstr) + 1];
		strcpy(_pstr, src._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;
	}
	//有效字符的个数,不包括'\0'
	int length()const
	{
		return strlen(_pstr);
	}
	//为了可以修改,返回引用,可以读可以改
	char& operator[](int index)
	{
		return _pstr[index];
	}
	//常对象,返回值不许修改,只读
	const char& operator[](int index)const
	{
		return _pstr[index];
	}
	const char* c_str()const
	{
		return _pstr;
	}
	//给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;
	};

	//容器的方法,不是迭代器的方法
	//begin容器底层首元素的迭代器表示,end容器末尾元素后继位置的迭代器的表示
	iterator begin()
	{
		return iterator(_pstr);
	}
	iterator end()
	{
		return iterator(_pstr+length());
	}
private:
	//String本质是对char* 指针的一个封装
	char* _pstr;
	friend String operator+(const String& lhs, const String& rhs);
	friend ostream& operator<<(ostream& out, const String& str);
};

//不delete会发生内存泄露,改后效率低下
/*
String operator+(const String& lhs,const String& rhs)
{
	char* ptmp = new char[strlen(lhs._pstr) + strlen(rhs._pstr) + 1];
	strcpy(ptmp, lhs._pstr);
	strcat(ptmp, rhs._pstr);
	String tmp(ptmp);
	delete[]ptmp;
	return tmp;
}
*/
String operator+(const String& lhs, const String& rhs)
{
	String tmp;
	tmp._pstr = new char[strlen(lhs._pstr) + strlen(rhs._pstr) + 1];
	strcpy(tmp._pstr, lhs._pstr);
	strcat(tmp._pstr, rhs._pstr);
	return tmp;

}

ostream& operator<<(ostream& out, const String& str)
{
	out << str._pstr;
	return out;
}
//char arr[] = "jkshshk"
int main()
{
	//迭代器的功能:提供一种统一得方式,来透明得遍历容器
	//透明:不需要知道迭代器底层得数据结构实现,不同数据结构得遍历被封装在++运算符里

	string str1 = "hellow world!";
	//str1 是容器,底层放了一组char类型的字符 
	//问题 如何遍历字符串容器

	//容器的迭代器类型(容器类型的嵌套类)
	//string::iterator it = str1.begin();
	//使用自动推导 简化代码
	auto it = str1.begin();
	
	for (; it != str1.end(); ++it)
	{
		cout << *it << " ";
	}
	cout << endl;
	cout << str1 << endl;

	//C++11
	//用于foreach的方式 遍历容器的内部元素的值
	//底层还是通过迭代器来遍历得
	for (char ch : str1)
	{
		cout << ch;
	}
	return 0;
}

在这里插入图片描述

vector

#include<iostream>
using namespace std;

//迭代器得所有遍历细节都被封装在++运算符重载中
//统一的方式遍历一个容器中所有得元素


template<typename T>
class Allocator
{
public:
	Allocator() {}
	~Allocator() {}

	T* allocate(size_t size)
	{
		return (T*)malloc(sizeof(T) * size);
	}
	void deallocate(void* p)
	{
		free(p);
	}
	void construct(T* p, const T& val)
	{
		new(p)T(val);
	}
	void destory(T* p)
	{
		p->~T();
	}
private:
};

template<typename T,typename Alloc = Allocator<T>>
class vector
{
public:
	vector(T size = 10, const Alloc& alloc = Allocator<T>())
		:m_alloctor(alloc)
	{
		m_first = m_alloctor.allocate(10);
		m_last = m_first;
		m_endl = m_first + size;
	}
	~vector()
	{
		for (T* p = m_first; p != m_last; ++p)
		{
			m_alloctor.destory(p);
		}
		m_alloctor.deallocate(m_first);
		m_first = m_last = m_endl = nullptr;
	}

	vector(const vector<T>& val)
	{
		int len = val.m_last - val.m_first;
		int size = val.m_endl - val.m_first;
		m_first = m_alloctor.allocate(size);
		for (int i = 0; i < size; i)
		{
			m_alloctor.construct(m_first + i, val.m_first + i);
		}
		m_last = m_first + len;
		m_endl = m_first + size;
	}
	vector<T>& operator=(const vector<T>& val)
	{
		if (this == &val)
		{
			return *this;
		}

		for (T* p = m_last; p != m_first; --p)
		{
			m_alloctor.destroy(p);
		}
		m_alloctor.deallocate(m_first);

		int len = val.m_last - val.m_first;
		int size = val.m_endl - val.m_first;
		m_first = m_alloctor.allocate(size);
		for (int i = 0; i < size; ++i)
		{
			m_alloctor.construct(m_first + i, val.m_first + i);
		}
		m_last = m_first + len;
		m_endl = m_first + size;
	}

	void push_back(const T& val)
	{
		if (full())
		{
			expand();
		}
		m_alloctor.construct(m_last, val);
		cout << "Push back:" << m_last << endl;
		m_last++;
	}
	void pop_back()
	{
		if (empty())
		{
			return;
		}
		m_last--;
		m_alloctor.destroy(m_last);
	}

	T back() const
	{
		return *(m_last - 1);
	}

	bool full() const { return m_last == m_endl; }
	bool empty() const { return m_last == m_first; }

	//迭代器
	//将vector当作数组下标来使用,重载[]运算符
	T& operator[](int index)
	{
		if (index < 0 || index >= (m_last-m_first))
		{
			throw"OutOfRangeException";
		}
		return m_first[index];
	}

	//迭代器,一般实现成容器的嵌套类型
	//不同的容器底层数据结构不同,那个具体的迭代方式不同,向外边提供的是迭代器运算符重载函数,把底层数据结构的差异性,都封装在了迭代器的重载函数中
	class iterator
	{
		public:
			iterator(T* ptr = nullptr)
				:_ptr(ptr)
			{

			}
			bool operator!=(const iterator& it)
			{
				return _ptr != it._ptr;
			}
			void operator++()
			{
				_ptr++;
			}
			//如果解引用不修改 可以改为常成员
			T& operator*()
			{
				return *_ptr;
			}
			const T& operator*()const
			{
				return *_ptr;
			}
		private:
			T* _ptr;
	};
	iterator begin() { return iterator(m_first); }
	iterator end() { return iterator(m_last); }
private:
	T* m_first;
	T* m_last;
	T* m_endl;
	Alloc m_alloctor;
	void expand()
	{
		int size = m_endl - m_first;

		T* ptmp = m_alloctor.allocate(2 * size);
		for (int i = 0; i < size; ++i)
		{
			m_alloctor.construct(ptmp + i, m_first[i]);
		}
		for (T* p = m_first; p != m_last; ++p)
		{
			m_alloctor.destory(p);
		}
		m_alloctor.deallocate(m_first);
		m_first = ptmp;
		m_last = m_first + size;
		m_endl = m_first + 2 * size;
	}
};

int main()
{
	vector<int> vec;
	for (int i = 0; i < 20; ++i)
	{
		vec.push_back(rand() % 100 + 1);
	}

	vector<int>::iterator it = vec.begin();
	for (; it != vec.end(); ++it)
	{
		cout << *it << endl;
	}

	//for each 底层原理是通过容器的迭代器来实现的
	for (auto a : vec)
	{
		cout << a<< endl;
	}

	//底层数组是连续的,提供中括号运算符重载是有意义的,随机访问效率 O[1]
	//底层不连续,就不支持中括号运算符重载,非线性
	//但是迭代器是通用的
	for (int i = 0; i < 20; ++i)
	{
		cout << vec[i] << endl;
	}

	cout << endl;
	return 0;
}

迭代器失效问题

#include<iostream>
#include<vector>
using namespace std;


/*
	迭代器失效问题
	扩容:原来的迭代器全部失效

	1.迭代器为什么会失效:
		调用eraser,当前到末尾全失效
		调用insert,当前到末尾全失效
		如果引起容器扩容,原来容器所有的迭代器全部失效
	2.迭代器失效了之后,问题该怎么解决
		对插入/删除点的迭代器进行更新操作
	3.不同容器的迭代器不能进行进行比较运算,两个不同内存的迭代器位置肯定不同

*/
int main()
{
	vector<int> vec;
	for (int i = 0; i < 20; ++i)
	{
		vec.push_back(rand() % 100 + 1);
	}

	for (int v : vec)
	{
		cout << v<<" ";
	}
	cout << endl;
	//将vector容器中所有的偶数全部删除
	auto it = vec.begin();
	for (; it != vec.end();)
	{
		if (*it % 2 == 0)
		{
			//迭代器失效,第一次调用erase以后,迭代器it就失效了
			//vec.erase(it);
			//break;
		
			//使用eraser等函数的返回值,返回了一个合法的迭代器(当前位置)
			//C++提供的函数,通过返回合法的迭代器解决了迭代器失效问题
			it = vec.erase(it);
			//由于是删除,生成了新的迭代器,就不需要++
		}
		else
		{
			++it;
		}
	}
	for (int v : vec)
	{
		cout << v<<" ";
	}
	cout << endl;

}

在vector中寻找迭代器失效的原理


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值