当前位置: 首页 > 文档资料 > C++大学教程 >

8.4 用作类成员与友元函数的运算符函数

优质
小牛编辑
114浏览
2023-12-01

运算符函数既可以是成员函数,也可以是非成员函数。非成员函数通常是友元函数。成员函数是用this指针隐式地访问类对象的某个参数,非成员函数的调用必须明确地列出该参数。

在重载运算符 ()、[]、->,或者任何赋值运算符时,运算符重载函数必须声明为类的一个成员。对于其他的运算符,运算符重载函数可以是非成员函数。
不管运算符函数是成员函数还是非成员函数,运算符在表达式中的使用方式是相同的。哪种实现方式更好呢?

当运算符函数是一个成员函数时,最左边的操作数(或者只有最左边的操作数)必须是运算符类的一个类对象(或者是对该类对象的引用)。如果左边的操作数必须是一个不同类的对象,或者是一个内部类型的对象,该运算符函数必须作为一个非成员函数来实现(正如8.5节中分别重载运算符<<和>>作为流插入运算符和流读取运算符一样)。运算符函数作为非成员函数直接访问该类的 private 或者 protected 成员时,该函数必须是一个友元。

重载的<<运算符必须有一个类型为 ostream& 的左操作数(例如表达式 cout<<classObject 中的 cout),因此它必须是一个非成员函数。类似地,重载>>运算符必须有一个类型为 istream& 的左操作数(如表达式 cin >> classObject 中的 cin),所以它也必须是一个非成员函数。此外,这两个重载的运算符函数都需要访问输出或输入的类对象的private数据成员,因此出于性能考虑,这些重载的运算符函数通常都是类的友元函数。

性能提示 8.1
可以把一个运算符作为一个非成员、非友元函数重载。但是,这样的运算符函数访问类的 private 和 protected 数据时必须使用类的 public 接口中提供的 set 或者 get 函数(即设置数据和读取数据的函数)、调用这些函数的开销会降低性能,因此必须内联这些函数以提高性能。

只有当二元运算符的最左边的操作数是该类的一个对象时,或者当一元运算符的操作数是该类的一个对象时.才需调用特定类的运算符成员函数。

选择非成员函数重载运算符的另外一个原因是使运算符具有可交换性。例如:假定有 longint 类型的一个对象 number 和类 HugeInteger 的一个对象 bigInteger1(本章的练习中开发了类 HugeInteger,该类中的整数可以是任意大小,不受机器字长的限制)。如果要求加法运算符(+)生成一个临时的 HugeInteger 对象,它是 HugeInteger 和longint类型对象的和(如表达式 bigInteger1+number),或者是 longint 和 HugeInteger 类型对象的和(如表达式number+bigIntegerl),那么上述的加法运算符就要具有可交换性(正如通常的加法一样)。

问题在于,如果把运算符作为成员函数重载,类的对象必须出现在运算符的左边,所以要将运算符函数作为一个非成员的友元重载,这样才能允许 HugeInteger 对象出现在加法运算符的右边。处理 HugeInteger 对象在左边的 operator+函数依然可以是一个成员函数。记住,非成员函数不一定要是友元,只要类的 public 接口中有相应 set 和 get 函数,有内联的 set 和 get 函数则更好。