码迷,mamicode.com
首页 > 其他好文 > 详细

再看 运算符重载

时间:2014-11-26 16:38:25      阅读:100      评论:0      收藏:0      [点我收藏+]

标签:style   io   ar   color   os   sp   for   数据   on   

运算符重载:分为 全局函数重载 和 成员函数重载两种:

1:重载输入输出操作符:

第一版:全局函数重载:

// 运算符重载3.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
#include <ostream>
using namespace std;
class Test
{
public:
	int i;
	int j;

	Test()
	{
		i = j = 0;
	}
	Test(int a, int b)
	{
		i = a;
		j = b;
	}
};

ostream& operator <<(ostream& out,const Test& t)
{
	out<<t.i<<" "<<t.j<<endl;
	return out;
}

istream& operator >>(istream& in, Test& t)
{
	in>>t.i>>t.j;
	if (in.fail())
	{
		cout<<"error"<<endl;
	}
	return in;
}
int _tmain(int argc, _TCHAR* argv[])
{
	Test t0;
	Test t1(3,4);
	cout<<t0<<t1<<endl;

	Test t3;
	cin>>t3;
	cout<<t3;
	getchar();
	return 0;
}

第二版:友元全局函数重载:

// 运算符重载3.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
#include <ostream>
using namespace std;

class Test
{
private: //注意这里为private
	int i;
	int j;
public:
	Test()
	{
		i = j = 0;
	}
	Test(int a, int b)
	{
		i = a;
		j = b;
	}
	//严格的来说,运算符重载跟友元函数没有任何关系,之所以要用友元函数,是因为这里的i跟j是private类型,我们编写<< and >>的重载
	//本来应该是属于全局变量函数重载的方式,但是全局函数没有访问i和j的权限,所以这里就声明为友元函数,使得可以访问i和j
	//看网上有人说:运算符重载分为:成员函数重载与友元函数重载,严格来说不可以这么说,应该分为全局函数重载与成员函数重载
	friend ostream& operator<<(ostream& out,const Test& t);
	friend istream& operator >>(istream& in, Test& t);
	//istream& operator >>(istream& in, Test& t);//ERROR  参数过多
};

//<< 与 >>运算符重载不可以为成员函数重载,因为那样相当于会有三个参数(还有一个this)
ostream& operator <<(ostream& out,const Test& t)
{
	out<<t.i<<" "<<t.j<<endl;
	return out;
}
istream& operator >>(istream& in, Test& t)
{
	in>>t.i>>t.j;
	if (in.fail())
	{
		cout<<"error"<<endl;
	}
	return in;
}

int _tmain(int argc, _TCHAR* argv[])
{
	Test t0;
	Test t1(3,4);
	cout<<t0<<t1<<endl;

	Test t3;
	cin>>t3;
	cout<<t3;
	getchar();
	return 0;
}


//严格的来说,运算符重载跟友元函数没有任何关系,之所以要用友元函数,是因为这里的i跟j是private类型,我们编写<< and >>的重载
 //本来应该是属于全局变量函数重载的方式,但是全局函数没有访问i和j的权限,所以这里就声明为友元函数,使得可以访问i和j
 //看网上有人说:运算符重载分为:成员函数重载与友元函数重载,严格来说不可以这么说,应该分为全局函数重载与成员函数重载

2:成员函数重载与全局函数重载的区别:

// 运算符重载.cpp : 定义控制台应用程序的入口点。
#include "stdafx.h"
#include <iostream>
using namespace std;

class CComplex
{
public:
	double m_i;//
	double m_j;//
	CComplex()
	{
		m_i = m_j;
	}
	CComplex(double m_i, double m_j = 0)
	{
		this->m_i = m_i;
		this->m_j = m_j;
	}
	//成员函数重载;在类的内部实现单目运算是无参函数
	CComplex operator-()
	{
		CComplex t(this->m_i,this->m_j);
		t.m_i *= -1;
		t.m_j *= -1;
		return t;
	}
	//类的内部实现双目运算符是1个参数,只要带入右值,左值用this代替
	/*
	CComplex operator+(const CComplex rhs)
	{
		CComplex t;
		t.m_i = m_i + rhs.m_i;
		t.m_j = m_j + rhs.m_j;
		return t;
	}
	*/

	//成员函数运算符重载*
	const CComplex operator*(const CComplex& rhs) 
	{
		CComplex t;
		t.m_i = this->m_i * rhs.m_i;
		t.m_j = this->m_j * rhs.m_j;

		return t;
	}

	void Print()
	{
		cout<<"输出:"<<m_i<<" "<<m_j<<endl;
	}
};

/*
//负号重载,并不是想改变里面参数的数据,比如i为3,并不是要把这里的i改为-3;只是在它前面加上负号;所以返回一个临时对象
CComplex operator-(const CComplex& c)//如果在函数里面不会改变参数本身,那么就设置为const参数
{
	//如果返回的是一个临时对象,那么函数返回值就是返回对象,不能返回引用(临时对象在函数结束会销毁,引用成为了孤立的)
	CComplex t = c;
	t.m_i = t.m_i * (-1);
	t.m_j = (-1) * t.m_j;
	return t;
}
*/
CComplex operator+( const CComplex& c1,  const CComplex& c2)
{
	CComplex c;
	c.m_i = c1.m_i + c2.m_i;
	c.m_j = c1.m_j + c2.m_j;

	return c;
}

//全局函数
CComplex operator *(const CComplex& lhs,const CComplex& rhs)
{
	CComplex t;
	t.m_i = lhs.m_i * rhs.m_i;
	t.m_j = lhs.m_j * rhs.m_j;
	return t;
}
int _tmain(int argc, _TCHAR* argv[])
{
	/*
	CComplex test(33,44);
	(-test).Print();
	//-test.Print(); ERROR 符号优先级的原因
	CComplex test2;
	test2 = -test;
	test2.Print();
	*/
	
	/************************************************************************/
	/*operator+                                                             */
	/************************************************************************/
	CComplex c1(2,3);
	CComplex c2(3,4);
	CComplex c3 = 1+c2;
	c3.Print();
	
	/************************************************************************/
	/*operator*                                                             */
	/************************************************************************/

	CComplex a1(1,2);
	CComplex a2(2,3);
	CComplex a3 = a1 * a2;
	CComplex a4 = a1.operator*(a2);
	a4.Print();
	a3.Print();

	/************************************************************************/
	/*operaotr*                                                             */
	/************************************************************************/

	CComplex a5 = a1 * 3;//3 会隐式转换,这里调用的是成员函数的operator*
	a5.Print();
	//CComplex a6 = 4*a1; //error C2677: 二进制“*”: 没有找到接受“CComplex”类型的全局运算符(或没有可接受的转换)
	//a6.Print(); 


	//如果有全局的operator*  则可以编译通过;
	CComplex a6 = 4*a1;
	a6.Print();

	/************************************************************************/
	/* operator* 要声明为CComplex的友元函数吗?不需要,全局函数就可以实现要求*/
	/************************************************************************/
	getchar();
	return 0;
}


3:前置++与后置++的操作符重载

// 运算符重载2.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
using namespace std;

class CComplex
{
public:
	CComplex()
	{
		m_i = m_j = 0;
	}
	CComplex(int a, int b = 0)
	{
		m_j = b;
		m_i = a;
	}
	void Print()
	{
		cout<<"m_i = "<<m_i<<" "<<"m_j = "<<m_j<<endl;
	}

	/*
	CComplex operator ++(int)
	{
		CComplex ret(*this);

		this->m_j++;
		this->m_i++;

		return ret;
	}

	CComplex& operator ++()
	{
		++m_i;
		++m_j;

		return *this;
	}
	*/

public:
	int m_i;
	int m_j;
};

//前置++
CComplex& operator++(CComplex& c) //1:返回的是参数本身,所以函数返回对象的引用,2:因为在函数当真会修改参数的值,所以参数不是const
{
	++c.m_i;
	++c.m_j;
	
	return c;

}

//后置++
CComplex operator++(CComplex& c,int)//1:这里返回一个临时变量,所以返回值只能是对象,不能是引用;2:因为在函数当真会修改参数的值,所以参数不是const
{
	CComplex ret = c;

	++c.m_i;
	++c.m_j;

	return ret;
}



int _tmain(int argc, _TCHAR* argv[])
{

	CComplex c1(1,3);
	++c1;
	c1.Print();

	CComplex c2(1,3);
	CComplex c3 = c2++;
	c3.Print();

	getchar();
	return 0;
}


前置++与后置++通过一个占位参数来区别

 

4:重载赋值操作符以及为什么复制操作符必须重载为成员函数

// 运算符重载4.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
using namespace std;


class MyCArry
{
private:
	int  m_iLength;
	int* m_pSpace;

public:
	MyCArry()
	{
		m_iLength = 0;
		m_pSpace  = NULL;
	}
	MyCArry(int length)
	{
		if (length < 0)
		{
			length = 0;
		}
		m_iLength = length;
		m_pSpace = new int(length);
		
	}
	MyCArry(const MyCArry& test)
	{
		m_iLength = test.m_iLength;
		m_pSpace  = new int(m_iLength);
		for(int i = 0; i < m_iLength; i++)  
	    {  
			   m_pSpace[i] = test.m_pSpace[i];  
		}  

	}

	/*
	MyCArry& operator = (const MyCArry& rhs)
	{
		//注意要有自赋值检查
		if ( this == &rhs)
		{
			*this = rhs;
		}
		this->m_iLength = rhs.m_iLength;
		delete m_pSpace;
		m_pSpace = new int(m_iLength);
		for(int i = 0; i < m_iLength; i++)  
		{  
			m_pSpace[i] = rhs.m_pSpace[i];  
		}  

		return *this;
	}
	*/
	//改进版本防止出现异常的时候内存泄漏
	MyCArry& operator = (const MyCArry& rhs)
	{
		int* pOrig = m_pSpace;//记住原先的m_Space;
		this->m_iLength = rhs.m_iLength;
		m_pSpace = new int(m_iLength);
		for(int i = 0; i < m_iLength; i++)  
		{  
			m_pSpace[i] = rhs.m_pSpace[i];  
		}  
		delete pOrig;//删除原先的m_pSpace
		return *this;
	}

};
//MyCArry& operator = (const MyCArry& rhs)  这里会报错误:operator = 必须是成员函数
//对于赋值操作符(=)--比较特别,因为任何类如果不提供显示的拷贝赋值(即重载=),则编译器会隐式地提供一个。
//这样的话,如果你再通过友元声明,进行全局的定义会造成调用二义性(即使允许,编译也会出错)。
//=,[],(),->  只能声明为成员函数,是为了避免不合法的书写编译通过(推测。。。。。)(出现1=;1[],1(),1->;等这些格式)
//其实这里+ ,+=等操作符,为类成员函数的时候: 1+a;编译不通过;为全局成员函数的时候:1+a;编译通过
//所以这里不用纠结为什么= [] () ->不能重载为全局函数,就是C++的规定,至于为什么,实在是找不到原因,找到的也都没有说服力
int _tmain(int argc, _TCHAR* argv[])
{

	MyCArry t1(5);
	MyCArry t2;
	t2 = t1;


	return 0;
}

/*
在实际开发过程中,单目运算符建议重载为成员函数,而双目运算符建议重载为友元函数。
通常下双目运算符重载为友元函数比重载为成员函数更方便,但是有时双目运算符必须重载为成员函数,
例如赋值运算符=。还有如果需要修改对象内部的状态,一般可以选择利用类成员函数进行修改。

*/


//MyCArry& operator = (const MyCArry& rhs) 这里会报错误:operator = 必须是成员函数//对于赋值操作符(=)--比较特别,因为任何类如果不提供显示的拷贝赋值(即重载=),则编译器会隐式地提供一个。

//这样的话,如果你再通过友元声明,进行全局的定义会造成调用二义性(即使允许,编译也会出错)。

//=,[],(),-> 只能声明为成员函数,是为了避免不合法的书写编译通过(推测。。。。。)(出现1=;1[],1(),1->;等这些格式)

//其实这里+ ,+=等操作符,为类成员函数的时候: 1+a;编译不通过;为全局成员函数的时候:1+a;编译通过

//所以这里不用纠结为什么= [] () ->不能重载为全局函数,就是C++的规定,至于为什么,实在是找不到原因,找到的也都没有说服力

 

总结:

要选择哪种方式重载也没有一个确切的说法,要看具体情况,例如+,+=,是双目运算符,重载为成原函数可以避免出现 1 = a;1 +=a;这样的格式,但是*乘法具有

交换率, bubuko.com,布布扣 1*a; a*1;这两种格式都要支持,那么用全局函数重载好;

 

记住 << >>必须是全局函数重载

记住 = [] () ->必须是成员函数重载

其余的都看具体情况

 

 

再看 运算符重载

标签:style   io   ar   color   os   sp   for   数据   on   

原文地址:http://blog.csdn.net/djb100316878/article/details/41516137

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!