现在的位置: 首页 > 综合 > 正文

C++进阶——运算符重载

2018年04月25日 ⁄ 综合 ⁄ 共 3185字 ⁄ 字号 评论关闭

1、运算符重载限制

       四种不可重载的运算符,它们是.    .*    ::   ?:

       运算符重载不可以改变运算符运算优先级;

       运算符重载不可以改变运算符的结合律(从右到左结合或从左到右结合);

       运算符重载不可以改变运算符的元数(二元运算符重载之后仍然是二元运算符);

       运算符重载不可以创造新的运算符。

2、运算符重载函数的使用

       运算符函数可以是类的成员函数,也可以全局函数。出于性能方面的考虑,全局运算符函数一般定义为友元函数。如果要重载()、[]、->或者任何赋值运算符,那么运算符函数必须声明为类的成员函数。如果运算符的左操作数必须是不同类的对象(也就是说如果我们想把运算符函数声明为类A的成员函数,但这个运算符的左操作数是类B的对象)或者是一个基本类型对象,那么运算符函数必须声明为全局函数。例如,重载(流插入符>>和)流提取符<<时,在函数operator<<()中cout<<classObject语句中<<流提取符的左操作数是ostream
&,并不是我们期望的类的对象classObject,这时候operator<<()要声明为全局函数。具体见本文最后的例子。

       综上,运算符函数定义为类的成员函数仅适用于以下两种情况:第一,当二元运算符的左操作数确实是该类的对象时;第二,当一元运算符的操作数为该类的对象时。

3、示例代码

示例一:(注意看下面连个程序的第29行和第33行,尤其是第二个程序的33行运算符函数参数次序问题)

因为我们把<的第一个操作数为当前类的对象,所以运算符函数被定义为成员函数

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

class A
{
private:
	string str;
public:
	A(string str);
	bool operator<(const A& a);
};
A::A(string str)
{
	this->str = str;
}

bool A::operator<(const A& a)
{
	if(this->str < a.str)//成员函数可以直接访问private变量
		return true;
	else
		return false;
}

int main()
{
	A a1("abcde"),a2("abcde");
	if(a1<a2)//会被处理为a1.operator<(a2)
		cout<<"a1<a2"<<endl;
	else
		cout<<"a1>=a2"<<endl;
	return 0;
}

下面我们看看运算符函数被定义为全局函数的情况 (特别注意第33行a1和a2在运算符函数中的次序分配问题)

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

class A
{
private:
	string str;
public:
	A(string str);
	string getStr() const;
	friend bool operator<(const A& a, const A& b);
};
A::A(string str)
{
	this->str = str;
}
string A::getStr() const
{
	return this->str;
}
bool operator<(const A& a, const A& b)
{
	if(a.getStr() < b.getStr())//非成员函数不可以直接访问private变量
		return true;
	else
		return false;
}

int main()
{
	A a1("abcdf"),a2("abcde");
	if(a1<a2)//会被处理为operator<(a1,a2)
		cout<<"a1<a2"<<endl;
	else
		cout<<"a1>=a2"<<endl;
	return 0;
}

示例二:(重点看运算符<<的重载)

#include <iostream>
#include <deque>
#include <stdexcept>
using namespace std;

#define EXIT_FAILURE -1

template <typename T>
class CLStack
{
private:
	deque<T> elems;
public:
	void push(const T& e);
	void pop();
	T top() const;
	bool isEmpty() const;
	template <typename T2>
	CLStack<T> & operator=(const CLStack<T2> &stack);
	
	//因为friend函数是类外函数,所以模板参数要用U防止与T冲突
	template <typename U>
	friend ostream &operator<<(ostream &output, CLStack<U> &stack);
};
template <typename T>
void CLStack<T>::push(const T& e)
{
	elems.push_back(e);
}

template <typename T>
bool CLStack<T>::isEmpty() const
{
	return elems.empty();	
}
template <typename T>
void CLStack<T>::pop()
{
	if(isEmpty())
	{
		throw std::out_of_range("Stack<>::pop: empty stack");
	}
	elems.pop_back(); // 移除最后一个元素
}

template <typename T>
T CLStack<T>::top() const
{
	if(isEmpty())
	{
		throw std::out_of_range("Stack<>::top: empty stack");
	}
	return elems.back();
}

template <typename T>
template <typename T2>
CLStack<T>& CLStack<T>::operator=(const CLStack<T2>& stack)
{
	if((void *)this == (void *)&stack)
		return *this;
	CLStack<T2> tmp(stack);	//拷贝构造函数
	elems.clear();
	while(!tmp.isEmpty())
	{
		elems.push_front(tmp.top()); 
		tmp.pop();
	}
	return *this; 
}

template <typename U>
ostream &operator<<(ostream &output, CLStack<U> &stack)
{
	while(!stack.isEmpty())
	{
		output<<stack.top()<<" ";
		stack.pop();
	}
	output<<endl;
	return output;
}

int main()
{
	CLStack<int> int1Stack,int2Stack;
	int1Stack.push(1);
	int2Stack = int1Stack;
	try{

		cout<<int2Stack.top()<<endl;
//		int2Stack.pop();
//		int2Stack.pop();
	} catch(const exception& ex) {
		cerr<<"Catch Exception: "<<ex.what()<<endl;
		return EXIT_FAILURE;  // 传回错误状态码
	}	
//	cout<<int2Stack.pop()<<endl;
	CLStack<float> floatStack;
	floatStack = int2Stack;
	cout<<floatStack.top()<<endl;
	floatStack.push(2);
	cout << floatStack;
	return 0;
}

 

抱歉!评论已关闭.