标签: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;这样的格式,但是*乘法具有
交换率,
1*a; a*1;这两种格式都要支持,那么用全局函数重载好;
记住 << >>必须是全局函数重载
记住 = [] () ->必须是成员函数重载
其余的都看具体情况
标签:style io ar color os sp for 数据 on
原文地址:http://blog.csdn.net/djb100316878/article/details/41516137