一.重载的基础
1.概念
运算符与类的对象结合在一起使用,这个过程便是运算符重载。换言之,运算符的重载都是同类打交道的。
2.重载对象
运算符重载的对象可以是内部类型数据,也可以是用户自定义类型。对于一般的+、-、*、/这些运算符,可以作用于int,float,double类型是因为C++本身已经重载了这些运算符。
3.重载的意义
理论上运算符可以重载成任何意义的符号,例如 +被重载为类似减法意义的运算,但这样做会令人费解,因此只建议重载为类似于与该运算符作用于内部类型的对象时所表现的功能
二.运算符重载的限制
可以重载的运算符
不能重载的运算符
注意的是,new、delete 、new[]、delete[]、sizeof这几个也是运算符,而?:是唯一的三目运算符,也是不能重载的。
l 重载不能改变运算符的优先级
l 重载不能改变运算符的结合律
l 重载不能改变运算符操作数的个数(本身是一元运算符的不能重载成二元)
l 不能创建新的运算符,只有现有的运算符可以被重载。
小技巧
ü 运算符函数的参数至少有一个必须是类的对象或者是类的对象的引用,这规则是为了防止改变运算符对内部类型的对象的作用方式。
一.运算符函数作类成员还是友元?
在重载运算符()、[ ]、-> 或者任何赋值运算符时,重载函数必须声明为类的成员。对于其他运算符,可以是非成员函数。
至于何时用作成员,何时用作友元合适,大概有这么一条准则:
如果运算符是一个成员函数,则出现在操作数的最左边的操作数必须是该类的一个类对象,或者是对该类对象的引用。如一个复数类的+重载定义成这样:Complex operator+(const Complex & b) const,那么调用的时候必定是a.operator+(b) (假设a是Complex的一个对象),这时,运算符+的最左边正好是Complex 类的一个类对象,且只能是Complex的对象(或者是对象的引用)。
相反,作为非成员函数,它的最左边(出现在运算符的左边,或者是运算符函数的第一个参数)必须是一个不同类的对象或是内部类型的对象。如Complex这个类的<<宜定义为非成员类:friend ostream &operator <<(ostream & ,const Complex & b)。在调用cout<<b的时候(在<<左边是非Complex类),实际上会这样调用:operator<<(cout,b) (第一个参数是非Complex类)。
运算符函数被定义为非成员的另一个原因是使运算符具有可交换性。如a、b是两个不同类的对象,那么a+b 与 b+a均成立。我想,这还需要a、b类型之间有可转换性。但若作为成员函数,则在左边必须是运算符所在类的对象或对象引用。如+是a所在类中重载的,则只能有a+b,不能 b+a。
ü 书中建议<<、>>输出、输入运算符函数定义为友元函数。
一.重载一元运算符和二元运算符
非static成员函数或者带有一个参数的非成员函数,参数的类型必须是自定义类型的对象或对象的引用。而对于二元运算符重载的叙述也类似,二元运算符可以重载带有一个参数的非static成员函数,或两个参数的非成员函数(参数之一必须是类的对象或者是对象的引用)。为什么只能重载成非成员函数呢?因为static成员函数只能访问类的static数据成员,有局限性,而被重载的运算符应该是适合该类的一切对象数据,而不只是类的一个公共对象。
ü 重载一元运算符时,把运算符函数用作内的成员函数而不作友元函数。
五. 类型之间的转换
内部类型之间可以实现转换,而用户自定义的类之间的转换以及自定义类与内部类型之间的转换必须通过其他手段来实现。有两种手段可以实现:
1.构造函数技术
由带单个参数的构造函数构成,参数类型是待转换类型,该类的类型是转换的目的类型。因而此方法不能由自定义类转换到内置类型。
2.运算符技术
必须是一个成员函数,无参数,无需指定返回值类型。其返回值类型正好是其重载运算符的名字。形如 operator 目标类型() const
六.重载++与――
首先,重载++和――的函数可以是成员函数,也可以是友元。而运算符的前缀还是后缀则通过传递一个哑元常量值来区分。例如,当编译器遇到++a时,它会调用operator++(a);当遇到a++时,则会调用operator++(a,int)。
在声明后缀重载运算符时,这个int不能给任何默认值;定义函数的时候这个int可以给它一个变量名,也可以不给,它只是作一个标识,所以不必给变量名。如果给了变量名,并且打印这个变量值,总是0。