重载操作符与转换

来源:互联网 发布:充电宝牌子 知乎 编辑:程序博客网 时间:2024/05/23 00:04

C++ 允许我们重定义操作符用于类类型对象时的含义。如果需要,可以像内置转换那样使用类类型转换,将一个类型的对象隐式转换到另一类型。

重载操作符的定义

重载操作符是具有特殊名称的函数:保留字 operator 后接需定义的操作符号。像任意其他函数一样,重载操作符具有返回类型和形参表,如下语句:
Sales_item operator+(const Sales_item&, const Sales_item&);
声明了加号操作符,可用于将两个 Sales_item 对象“相加”并获得一个Sales_item 对象的副本。

除了函数调用操作符之外,重载操作符的形参数目(包括成员函数的隐式this 指针)与操作符的操作数数目相同。函数调用操作符可以接受任意数目的操作数。

可重载的操作符



不能重载的操作符



通过连接其他合法符号可以创建新的操作符。例如,定义一个 operator**以提供求幂运算是合法的。

重载操作符必须具有一个类类型操作数

用于内置类型的操作符,其含义不能改变。例如,内置的整型加号操作符不能重定义:
// error: cannot redefine built-in operator for ints
 int operator+(int, int);
也不能为内置数据类型重定义加号操作符。例如,不能定义接受两个数组类型操作数的 operator+。

重载操作符必须具有至少一个类类型或枚举类型的操作数。这条规则强制重载操作符不能重新定义用于内置类型对象的操作符的含义。

优先级和结合性是固定的

操作符的优先级、结合性或操作数目不能改变。不管操作数的类型和操作符的功能定义如何,表达式
x == y +z;
总是将实参 y 和 z 绑定到 operator+,并且将结果用作 operator== 右操作数。

有四个符号(+, -, * 和 &)既可作一元操作符又可作二元操作符,这些操作符有的在其中一种情况下可以重载,有的两种都可以,定义的是哪个操作符由操作数数目控制。除了函数调用操作符 operator() 之外,重载操作符时使用默认实参是非法的。

不再具备短路求值特性

重载操作符并不保证操作数的求值顺序,尤其是,不会保证内置逻辑 AND、逻辑 OR和逗号操作符的操作数求值。在 && 和 ||的重载版本中,两个操作数都要进行求值,而且对操作数的求值顺序不做规定。因此,重载 &&、|| 或逗号操作符不是一种好的做法。

类成员与非成员

大多数重载操作符可以定义为普通非成员函数或类的成员函数。作为类成员的重载函数,其形参看起来比操作数数目少 1。作为成员函数的操作符有一个隐含的 this 形参,限定为第一个操作数。

重载一元操作符如果作为成员函数就没有(显式)形参,如果作为非成员函数就有一个形参。类似地,重载二元操作符定义为成员时有一个形参,定义为非成员函数时有两个形参。

类 Sales_item 中给出了成员和非成员二元操作符的良好例子。我们知道该类有一个加号操作符。因为它有一个加号操作符,所以也应该定义一个复合赋值(+=)操作符,该操作符将一个 Sales_item 对象的值加至另一个Sales_item
对象。

一般将算术和关系操作符定义非成员函数,而将赋值操作符定义为成员:
// member binary operator: left-hand operand bound to implicit this pointer
Sales_item& Sales_item::operator+=(const Sales_item&);
// nonmember binary operator: must declare a parameter for each operand
Sales_item operator+(const Sales_item&, const Sales_item&);
加和复合赋值都是二元操作符,但这些函数定义了不同数目的形参,差异的原因在于 this 指针。当操作符为成员函数,this 指向左操作数,因此,非成员 operator+ 定义两个形参,都引用 const Sales_item 对象。即使复合赋值是二元操作符,成员复合赋值操作符也只接受一个(显式的)形参。使用操作符时,一个指向左操作数的指针自动绑定到 this,而右操作符限定为函数的唯一形参。

复合赋值返回一个引用而加操作符返回一个 Sales_item 对象,这也没什么。当应用于算术类型时,这一区别与操作符的返回类型相匹配:加返回一个右值,而复合赋值返回对左操作数的引用。

操作符重载和友元关系

操作符定义为非成员函数时,通常必须将它们设置为所操作类的友元。在本章的后面部分,将给出操作符可以定义为非成员的两个原因。在这种情况下,操作符通常需要访问类的私有部分。

Sales_item 类也是说明为何有些操作符需要设置为友元的一个好例子。它定义了一个成员操作符,并且有三个非成员操作符。这些非成员操作符需要访问私有数据成员,声明为友元:
class Sales_item {
friend std::istream& operator>>(std::istream&, Sales_item&);
friend std::ostream& operator<<(std::ostream&, const Sales_item&);
public:
Sales_item& operator+=(const Sales_item&);
};
Sales_item operator+(const Sales_item&, const Sales_item&);
输入和输出操作符需要访问 private 数据不会令人惊讶,毕竟,它们的作用是读入和写出那些成员。另一方面,不需要将加操作符设置为友元,它可以用public 成员 operator+= 实现。

使用重载操作符

使用重载操作符的方式,与内置类型操作数上使用操作符的方式一样。假定item1 和 item2 是 Sales_item 对象,可以打印它们的和,就像打印两个 int的和一样:
cout << item1 + item2 << endl;
这个表达式隐式调用为 Sales_items 类而定义的 operator+。也可以像调用普通函数一样调用重载操作符函数,指定函数并传递适当类型适当数目的形参:
// equivalent direct call to nonmember operator function
cout << operator+(item1, item2) << endl;
这个调用与 item1 和 item2 相加的表达式等效。调用成员操作符函数与调用任意其他函数是一样的:指定运行函数的对象,然后使用点或箭头操作符获取希望调用的函数,同时传递所需数目和类型的实参。对于二元成员操作符函数的情况,我们必须传递一个操作数:
item1 += item2; // expression based "call"
item1.operator+=(item2); // equivalent call to member operator function
两个语句都将 item2 的值加至 item1。第一种情况下,使用表达式语法隐式调用重载操作符函数:第二种情况下,在 item1 对象上调用成员操作符函数。

0 0
原创粉丝点击