一、运算符重载
运算符重载是一种形式的C++多态。
在C++中,编译器有能力把一个由数据、对象和操作符共同组成的表达式,解释为对一个全局或成员函数的调用。该全局或成员函数被称为操作符函数,通过重定义操作符函数,可以实现针对自定义类型(结构,类)的运算法则,并使之与内置类型一样参与各种表达式。
重载运算符可使代码看起来更加自然。
要重载运算符,需使用被称为运算符函数的特殊函数形式:
operator op (argument-list)
- operator是关键字
- op必须是有效的C++运算符,不能虚构一个新的符号
可重载的运算符
+ | - | * | / | % | ^ |
---|---|---|---|---|---|
& | | | ~= | ! | = | < |
> | += | -= | *= | /= | %= |
^= | &= | |= | << | >> | >>= |
<<= | == | != | <= | >= | && |
|| | ++ | – | , | ->* | -> |
( ) | [ ] | new | delete | new[ ] | delete[ ] |
操作符的分类
二、典型的单目运算符重载
运算符重载有两种方法:
一种是在类中以成员函数定义,则对于单目运算符来说由于类中会默认提供this指针,所以不需要其他参数;第二种是以全局函数实现,则由于没有this指针,需要有类作为形参。
设有这样一个类
class Number
{
int x;
int y;
public:
Number (void) { }
Number(int x,int y):x(x),y(y)
{
}
~Number() { }
};
作为成员函数时:
- 前++/–
Number& operator ++/-- (void)
{
this->x++;
this->y++;
return *this;
}
- 后++/–:后++/– 会先使用初始的值,等语句执行后在进行加减
Number operator ++/-- (int)//int为虚参
{
Number n(*this);//拷贝构造一个对象记录未++/--前的值
this->x++;
this->y++;
return n;
}
作为全局函数时:
可能会访问到参数的私有成员,解决方法:
- 1、把成员变成公开,但会破坏类的封闭性。
- 2、把全局函数声明为友元函数
友元的声明:
friend Number& operator ++ (Number &num);//前++
friend Number operator ++ (Number &num,int);//后++
前++/–
Number& operator ++/-- (Number& num) //++i
{
num.x++;
num.y++;
return num;
}
后++/–
Number operator ++/-- (Number &num,int)//int(虚参)用于区分前++/--和后++/--
{
Number n1 = num;
num.x++;
num.y++;
return n1;
}
三、典型的双目运算符重载
作为成员函数
Number operator /+-*%|^& (Number & that)
{
Number t; // 调用无参构造
t.x = x / that.x;
t.y = y / that.y;
return t; // 不能返回局部对象的引用,否则会出现悬空引用
}
注意:原对象的值不变,需要产生一个临时的对象存储值来传递
bool operator > < >= <= == != || && (Number & that)
{
return this.x > that.y;
}
判断运算符,返回bool值
Number & operator += -= *= /= (Number& that)
{
this->x += that.x;
this->y += that.y;
return *this;
}
会改变自身的值,应该返回类引用.
全局函数
Number operator + (Number& a,Number& b)
{
Number t(a.x+b.x,a.y+b.y);
return t;
}
同样也需要声明为友元函数。
四、输入、输出运算符重载
输入、输出运算符不能重载为成员函数,只能是友元。
//输出
ostream& operator << (ostream& os,Number & num)
{
cout << num.x << num.y << endl;
return os;
}
//输入
istream& operator >> (istream& is,Number & num)
{
return is >> num.x >> num.y;
}
//重载后就可以通过下面语句直接输入输出
Number n1;
cin >> n1;
cout << n1 << endl;
五、特殊的运算符的重载
- [ ] 下标运算符,可以把对象当作数组来使用。
- ( ) 函数运算符,可以把对象当作函数来使用。
- -> 成员访问运算符,可以把对象当作指针来使用。
- * 解引用运算符,可以把对象当作指针来使用。
- new/delete 也可以进行重载,但不建议使用。
- new会自动调用重载的new函数再构造函数。
- delete会先调用析构再调用重载的delete函数。
六、运算符重载的一些限制
1、不能重载的运算符
:: (作用域限定符) | . (成员访问运算符) | *(成员指针解引用) |
---|---|---|
?: (三目运算符) | sizeof (字节长度运算符) | typeid (类型信息操作符) |
2、运算符的重载改变不了运算符的优先级
3、无法改变运算符的操作个数
4、无法发明新的运算符
5、重载运算符要注意运算符的一致性,不要改变运算符默认的运算规则
6、运算符的重载是为了方便使用、增强可读。