按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
matrix operator+(matrix& A; matrix& B);
则上面的表达式被编译器解释为
C=operator+(A; B);
如果operator+被重载为类matrix的成员函数
matrix matrix::operator+(matrix& B);
则该表达式被解释为
…………………………………………………………Page 80……………………………………………………………
C=A。operator+(B);
初看起来,无论把操作符operator+重载为友元全局函数还是成员
函数,都可以实现同样的功能。的确,在很多情况下是这样的,
但是有些情况下,我们只能选择其中之一。考虑矩阵的数乘运
算,我们可能希望使用下面的表达式
B=3*A;
从数学意义上说,上面的表达式将3乘以A中的每一个元素,然后
将结果赋值给B。假设operator*的定义如下:
matrix matrix::operator*(matrix& A);
即是说我们将operator*函数定义为类的成员函数,这时,编译器
如何解释上面的代码呢?下面的解释方法是行不通的:
B=3。operator*(A);
因为3不是类matrix的一个实例对象,而且,编译器在这种情况下
并不会对左边的操作数作任何类型转换,也就是说,即使你为类
matrix定义了一个构造函数
matrix::matrix(int);
编译器仍然不会将前面的表达式解释为
B=matrix(3)。operator*(A);
因此,将运算符函数定义为类的成员函数是不可能实现我们的要
求的,这时,我们需要将函数operator*定义为全局函数,并且,
将它作为类matrix的友元,如下所示:
matrix operator*(int k; matrix& A);
这时,编译器将前面的表达式解释为
B=operator*(3; A);
由于存在合适的函数原型,因此编译器将调用上面所定义的函数
operator*来进行运算,并将结果赋予B。
上面的叙述容易给人一种感觉,即是说将运算符函数定义为友元
函数要比将它们定义为类的成员函数好得多。事实上很多情况下
也是这样,然而,并不是所有的函数都能够被定义为友元函数,
…………………………………………………………Page 81……………………………………………………………
以下的函数只能被定义为类的成员函数:
operator=
operator()
operator''
operator…》
° 注意:
° 函数operator=只能定义为类的成员函数,但是其它的二元重
合赋值运算符,如?? 、?? 、??和??等却不受此限,请看下面的
代码 :
两个函数中C++中是不同的重载形式。
由编译器自动生成的运算符函数operator所进行的默认操作
是将两个对象中的数据进行按成员拷贝,有一点需要强调的
是,对于其中的指针成员,拷贝的是指针本身,而不是指针
所指向的内容。如果在类中使用了指针成员,这是一个必须
注意的问题,一般来说,在这种情况下,我们必须提供自定
义的拷贝构造函数和以type&为参数的赋值运算符重载函数,
否则很容易引起指针挂起的问题。
表2。5总结了不同运算符的重载方法。比较特殊的是递增运算
符+ + 和递减运算符 ,特殊的原因是它们有两种不同的
形式,即前缀形式和后缀形式。如果区别运算符 “++”和 “
”的两种不同形式呢?我们为此作如下的约定,对于前缀
形式的递增/递减运算符,以和一般的一元运算符同样的方式
将它们重载为
type& type::operator++()
表2。5 不同运算符的重载方法小结
运算符 以友元函数方式进 以成员函数方式进行重载
行重载
一元运算符@ type operator@ type operator@()
(arg)
(不包括递增运 表达式A@或@A等价于
…………………………………………………………Page 82……………………………………………………………
算符++和递减 表达式A@或@A等价 A。operator@()
运算符??) 于operator@(A)
二元运算符@ type operator@ type operator@(arg)
(arg1; arg2)
表达式A@B等价于A。operator@
表达式A@B等价于 (B)
operator@(A; B)
赋值运算符= – type& operator=(arg)
表达式A=B等价于A。operator=
(B)
函数调用运算 type operator()(arg; 。。。)
符 ()
表达式A(arg; 。。。)等价于
A。operator()(arg; 。。。)
注意:
1。 函数调用运算符被当作一个
二元运算符,然而函数调用运
算符函数的参数表却可以拥有
多个参数。
2。 函数调用运算符作用于一个
类的实例对象,而不是一个函
数名。
关于函数调用运算符可以参见
前面的类matrix的实现。假设A
是类matrix的一个实例对象,
则表达式A(1;2)返回矩阵A中第
一行第二列的元素。
下标运算符'' type operator''(arg)
表达式A'arg'等价于
A。operator''(arg)
注意:
除了可以为整数以外,下标运
算符函数的参数arg还可以为任
何类型,比如,你可以创建一
个以字符串为下标的数据列
表。
成员函数运算 type operator…》(arg)
符…》
…………………………………………………………Page 83……………………………………………………………
表达式A…》arg等价于
A。operator…》(arg)
注意:
可以重载成员选择运算符 “
》”,但不可以重载另一个成员
选择运算符 “。”。
type& operator++(type&)
或
type type::operator…()
type operator…(type&)
要注意的是,如果使用将operator++和operator……重载为全
局友元函数,则参数要使用引用类型,这是因为一般来说,
运算符 “++”和 “”都需要修改操作符本身。
对于后缀形式的递增/递减运算符,我们约定使用下面的方式
来进行重载:
type& type::operator++(int)
type& operator++(type&; int)
或
type type::operator…(int)
type operator…(type&; int)
也就是说,我们使用一个额外的整型参数来表明所需调用的
是后缀形式的递增/递减运算符。这样,表达式
++A
对于编译器等价于
A。operator++()
或
operator++(A)
…………………………………………………………Page 84……………………………………………………………
而表达式
A++
对于编译器等价于
A。operator++(0)
或
operator++(A; 0)
运算符 “”与此类似。
这样,编译器就能有效的区分前缀形式的递增/递减运算符和
后缀形式的递增/递减运算符,对于Visual C++而言,传递给
后缀形式的递增/递减运算符函数的整型参数为0,事实上,
我们可以显式的调用后缀形式的递增/递减运算符函数,如
A。operator++(3);
或
operator++(A; 3);
这时,所传递的整型参数可以不是0,而且,后缀形式的运算
符函数operator++也的确可以使用这个参数,这时, “++”
运算符看起来有点像一个二元运算符,但是,要记住,后缀
形式的运算符函数operator++只是一个约定,对于C++来说,
无论使用的是前缀形式还是后缀形式,递增/递减运算符都是
一个一元运算符,下面的表达式在Visual C++中是通不过
的:
A++3;
不要想当然的将它解释为
A。operator++(3);
或
operator++(A; 3);
n 注意:
n 由表2。3可以知道,用于动态分配内存的运算符new和
…………………………………………………………Page 85……………………………………………………………
delete也可以被重载,但是,C++对这两个运算符的默认
实现非常之好,而且,由于Win32平台的32位平坦 内存管
理机制,在系统物理内存不足时会 自动使用磁盘交换文
件,因此,在绝大多数情况下,我们不需要、也不应该
重载new和delete运算符,而且,不正确或者说不完善的
重载new和delete有可能在动态分配内存时带来难以预料
的严重后果。也鉴于这个原因,本书中不再讲述重载new
和delete运算符的细节,若读者在程序中的确需要重载
它们的话,请参考Visual C++的联机文档或其它的C++文
献。
n 重载运算符时应该遵从惯例,比如说,我们可以重载运
算符 “+”来连接两个字符串,这是合乎我们的日常思维
方式的。同样,C++允许我们使用运算符 “”来连接两
个字符串,但是,这样的重载方式不会给编程带来