1、重载操作符必须具有至少一个类类型或枚举类型的操作数,这条规则强制重载操作符不能重新定义用于内置类型对象的操作符含义。
2、除了函数调用操作符operator( )之外,重载操作符时使用默认实参是非法的。
3、大多数重载操作符可以定义为普通非成员函数或类的成员函数。
作为类的成员重载函数,其形参看起来比操作数数目少1,因为它有一个隐含的this形参,限定为第一个操作数。作为普通函数时,函数的第一、第二个参数分别为操作符的左右操作数。
4、重载一元操作符如果作为类成员函数就没有形参,而作为非成员函数就有一个形参。
5、操作符定义为非成员函数时,通常将它们定义为操作类的友元。在这种情况下,操作符通常需要访问类的私有部分。
6、使用重载操作符有两种方式:
若+操作符是类A的成员函数:
1)item1+item2;
2)item1.operator+(iterm2);
若+操作符是普通函数:
1)item1+item2;
2)operator+(item1,item2);
7、赋值操作符、取地址操作符和逗号操作符在类类型操作数有默认含义。如果没有特定的重载版本,编译器就执行默认的操作。
当内置操作符与类型上的操作存在逻辑对应关系时,重载操作符最有用。使用重载操作符不是创造命名操作,可以令程序更自然。
8、将要用作关联容器键类型的类应当定义<操作符,关联容器默认使用键类型的<操作符。许多算法假定这些操作符存在,如find使用==操作符,sort算法使用<操作符。
9、赋值=,下标[],调用(),成员访问->等操作符,必须定义为类的成员函数,将它们定义为非成员函数将在编译时标记为错误。
10、重载<<和>>时,IO操作符必须为非成员函数。
因为操作符函数的参数顺序,就是操作符操作数的顺序。如果将其作为类的成员函数,那么左操作数必须为类类型的对象,形如item<
但是ostream是标准库的一部分,我们不能为标准库添加成员。
另外,ostream和istream必须为引用类型,因为流对象是不可以复制和赋值的。且返回值也为流对象的引用。
如:istream & operator>>(istream& in,A&s);
ostream& operator<<(ostream& out,A&s);
除了处理可能发生的错误之外,输入操作符可能还需要设置输入形参条件状态以指出失败。如failbit。
11、加法操作符,为了与内置操作符保持一致要返回一个右值,而不是一个引用。
算术操作符通常产生一个新值,是两个操作数计算的结果,它不同于任一操作数且在一个局部变量中计算,返回那个变量的引用是一个运行时错误。
与加法操作符相比,复合赋值操作+=效率更高,因为它不必创建和撤销一个临时变量来保存计算结果。
12、赋值操作符必须是类的成员函数,以便编译器知道是否需要合成一个。为了与内置类型一致,赋值操作符需要返回*this的引用。注意要防止自我赋值。
13、下标操作符同样必须为类的成员函数。它返回左值。可以定义const类型和非const类型的下标操作符函数。当被const对象调用时返回const引用。被非const调用时,返回非const引用。
14、重载箭头操作符时,如Screen* opeator->(return ptr->sp;);
它可能表现的像二元操作符一样:接受一个对象和一个成员名。其必须定义为成员函数。
当通过箭头操作符进行调用时,如p->display(item);
其实相当于(p.operator->())->display(item);
p.operator->()的返回值调用display。这要特别注意。
另外它必须返回执行类类型的指针或者返回定义了自己的箭头操作符的类类型的对象。
15、重载前置自增自减操作符的形式为:A&operator++();后置为A& opearator++(int);
因为没有使用int形参,所以没有为其命名,虽然在使用时可以为后置运算符提供额外的形参,但通常不这样做,这个形参不是后缀式正常工作所必需的,它唯一的作用是将前置与后置自增自减操作符区分开来。
在一般使用中编译器根据运算符的位置,判断是使用前置还是后置运算符。但是当显式调用时就不能省略传递的int类型的形参了,如:
item.operator++( )//前置
item.operator++(0);//后置
为了与内置操作符一致,后缀式操作符应返回旧值,即尚未自增或自减的值,并且应作为值返回,而不是返回引用。
16、可以为类类型的对象重载函数调用操作符。一般为表示操作的类重载调用操作符。如
class absint尽管a是一个对象而非函数,我们仍然可以调用该对象。像这种定义了调用操作符的类,我们称之为函数对象。即它们是行为类似函数的对象。
函数调用操作符必须声明为成员函数。一个类可以定义函数调用操作符的多个版本,由形参的数目或类型加以区别。
17、函数对象通常用作标准库算法的实参。这是因为函数对象比函数更灵活。
如count_if函数,它需要一对迭代器和一个函数。它要求的函数只能有一个形参且返回bool类型。该函数用于判断传入的字符串是否满足一定的要求,如长度是否大于10;理想情况下,我们能够将要判断的长度作为参数,传递给这个函数,但是由于它只有一个形参,用于传递字符串。因此我们会将10这个数字固化到程序中,灵活性大打折扣。
这个count_if传递一个GT_cls类型的对象而不再是函数,GT_cls(6)将产生一个临时对象。这个count_if每次调用函数形参时,都会使用GT_cls的调用操作符。
每个函数对象类表示一个给定的操作符。即每个类都定义了应用命名操作的调用操作符。且每个函数对象类都是类模板,需要为该模板提供一个类型。
1)绑定器:bind1st和bind2st,每个绑定器接受一个函数对象和一个值,bind1st将给定值绑定到二元函数对象的第一个实参,bind2st绑定到第二个实参。
2)求反器:它将谓词函数对象的真值求反。21、单参构造函数可以执行实参向类类型的隐式转换。
除了这种转换之外,我们还可以定义从类类型到其他类型的转换。我们可以定义转换操作符,给定类类型的对象,这种操作符将产生其他类型的对象。
转换操作符是一种特殊的类成员函数,它定义将类类型的值转变为其他类型值得转换。转换操作符必须是类的成员函数,在保留字operator之后跟着转换的目标类型,这个目标类型就是函数的返回值,因此它不能指定返回类型,且形参表必须为空。因为本类就是它的参数。如:对任何可作为函数返回类型的类型都可以定义转换函数。一般而言,不允许转换为数组或函数类型,但可以转换为指针或引用类型。
22、转换函数一般不改变被转化的对象,因此通常被定义为const。
转化函数在以下条件下会被调用:
1)在表达式中,如A a; double d; a>=d;
2)在条件中,if(a);
3)将实参传给函数或从函数返回值。int cal(int); int i=cal(a);
5)在显式类型转换中。int i=static_cast
因此可以再需要A的地方使用B,在需要int的地方使用A,但是不能再需要int的地方使用B。因为从B到int需要两次转换,但是语言只允许一次类类型转换。所以这是错误的。
24、接下来介绍怎样用类类型转换将实参和相应形参相匹配。
一般说来,给出一个类与两个内置类型之间的转换不是好的做法。当两个类定义了相互转换时,很可能存在二义性。func(b);
b可以用两种不同的方式转换为A的对象。编译器可以接受B类型对象的构造函数,也可以将调用B中的转换函数。这就有了二义性。
为了消除这种情况,需要显式调用转换操作函数或构造函数。如
func(b.operator A());
func(A(b));
另外一个错误:
class A