1) 运算符重载的原则
l 不要出现歧义或误解
如果别人用这个重载会误解它的本来意义,那么放弃这个重载
l 当重载可以使得代码更易读或易写时
l 不能重载不存在的运算符,比如**(求幂),这涉及到定义优先级
l 不能改变运算符的优先级和参数个数,防止用起来很混乱
l 优先考虑成员重载,实在不行才用非成员重载
2) 成员重载
l 成员重载要求左参数一定是本类对象
Integer& operator + (Integer& a)
{
return Integer( this.value + a.value);
}
l 建议所有的一元运算符都是成员重载
原因是,它只有一个参数,参数肯定是类的对象。如果参数是另外一个类的对象,那是另外一个类的重载了。
比如,+ -(正负号),++,--,~,*,&等都是可重载的一元运算符。
l 建议所有数学及逻辑运算符都是成员重载
原因是,如果左右参数不是同一个类型的对象时,容易出现理解的混乱,使用者难以正确的使用。
比如,+-*/,+=,-=,*=,/=,<,>,>>, <<等。
l =, (),[],->,->*必须是成员重载
3) 非成员重载
当第一个参数和其他参数可以是不同类型的数据时,可以考虑非成员重载。
比如:ostream& operator << (ostream& os, const A& a);
4) 不能重载的运算符
l .和.*
这两个运算符对于所有类型都有意义,如果重载了它们,导致不能正常访问成员数据
l C/C++不存在的运算符不能重载
5) 特殊的运算符重载
l 赋值 =
1) 为了实现 a=b=c,必须返回引用;
2) 为了(a=b).Func1(),这个引用不能是const的,否则只能调用const函数。
A& operator = ( const A& a)
{
if( this == &a)
{
return *this;
}
//拷贝
return *this;
}
l 自增自减 ++,--
如果区别a++或++a呢,用哑数据表示
Integer& operator++(){this.value++; return *this;}; //++a
Integer operator++(int){Integer tmp; //++操作; return tmp;} //a++
可以看见,a++返回的是非引用对象,原因是返回值是一个临时对象
l 括号 ( )
1) 自动类型转换
没有写返回值,但是,会返回( )前面定义的类型。
class B{};
class A
{
public:
operator B() const {return B();}; //B必须是存在
的类型
}
void Func(B& b);
A a;
Func(a); //会调用A类的( )重载,转换成B的对象
2) 一般( )重载
class A
{
public:
bool operator ()( int a, int b )
{
return true;
}
};
A a;
bool b = a(3,9);
提示:一般用于函数对象,当做函数来调用。
一般和->*一起用。
l ->
一般用于返回一个对象指针(类里的指针成员)。它必须返回一个对象或指针。
class Object
{
public:
void Func();
}
class A
{
Object* operator -> () const{return pObj;}
};
A a;
a->Func(); //调用Object类的函数
l ->*
这个是二元操作符!一般用于函数对象,它必须返回一个对象。
class FunctionObject
{
public:
Object* pObj;
typedef int (*FuncPointer)(int, float);
FuncPointer fPointer;
int operator() (int a, float b)
{
return (pObj->*fPointer)(a,b);
//普通函数指针函数调用
}
};
class Object
{
public:
int Add(int, float);
FunctionObject operator->*(FuncPointer p)
{
return FunctionObject( this, p);
}
}
Object obj;
(obj->*Add)(1, 1.3f);
//obj是->*的左参数,Add是有参数,一个函数指针
//返回值是一个FunctionObject对象,然后调用( )重载函
数。