详谈C++ 重载运算符中友元函数和成员函数

    xiaoxiao2024-11-18  68

    1.不能被重载的运算符有五个,分别是 . .* :: ?: sizeof 有两个运算符系统提供默认重载版本: (1.)赋值运算符“=”,系统默认重载为对象数据成员的复制。 (2.)地址运算符“&”,系统默认重载为返回任何类对象的地址。 2.运算符函数可以重载为成员函数,友元函数和普通函数。使用非成员,非友元的普通函数重载访问private,protect数据成员时,必须通过public接口提供的函数实现,增加程序开销。所以重载运算符用成员函数或友元函数。他们的关键区别在于,成员函数有this指针,而友元函数没有this指针。 (1.) 一元运算符(无论前置还是后置,都要求有一个操作数) Object op 或 op Object <1> 当重载为成员函数,编译器解析为: Object.operator op() 操作数由对象Object通过this指针隐含传递,所以参数表为空。 <2>当重载为友元函数时,编译器解析为: operator op(Object) 函数operator op所需的操作数由参数表Object提供。 (2.)二元运算符(要求有左、右操作数) ObjectL op ObjectR <1>当重载为成员函数,编译器解析为: ObjectL.operator op (ObjectR) 左操作数ObjectL通过this指针传递,右操作数由参数ObjectR传递。 <2>重载为友元函数时,编译器解析为: operator op(ObjectL,ObjectR) 左、右操作数都由参数传递。 (1.)用成员函数重载运算符(当一元运算符的操作数,或者二元运算符的左操作数是该类的一个对象时,重载运算符函数一般定义为成员函数)

    #include<iostream> using namespace std; class TriCoor ///描述3维坐标的类 TriCoor, { public: TriCoor(int mx = 0, int my = 0, int mz = 0) { x = mx; y = my; z = mz; } TriCoor operator + (TriCoor t) { TriCoor temp; temp.x = x + t.x; temp.y = y + t.y; temp.z = z + t.z; return temp; } TriCoor operator = (TriCoor t) { x = t.x; y = t.y; z = t.z; return *this; } TriCoor operator ++ () { x++; y++; z++; return *this; } void show() { cout << x << " , " << y << " , " << z << "\n"; } void assign(int mx, int my, int mz) { x = mx; y = my; z = mz; } private: int x, y, z; // 3_d coordinates }; int main() { TriCoor a(1, 2, 3), b, c; a.show(); b.show(); c.show(); for (int i = 0; i < 5; i++) ++b; b.show(); c.assign(3, 3, 3); c = a + b + c; c.show(); c = b = a; c.show(); }

    程序中,*this是引起调用函数的对象,他是运算符的左操作数。例如,表达式:a+b激活函数的是对象b,运算符右边的对象被作为参数传递给函数。因此,该表达式解析为:a.operator+(b)。 程序中,重载“++”和“=”运算符函数返回类类型的引用TriCoor &。“++”和“=”的运算可以作为左值表达式函数返回类引用既符合原来的语义,有减少函数返回时对匿名对象数据复制的开销。 用友元函数重载运算符 ##不能用友元函数重载的运算符有 = () 【】 -> 四个

    当运算符左右操作数类型不用时,用成员函数重载运算符会碰到麻烦。 例如:

    class Complex { public: Complex(int a) { Real = a; Image = 0; } Complex(int a,int b) { Real = a; Image = b; } Complex operator+(Complex); private: int Real; int Image; //...... }; int main() { Complex z1(1, 1), z2(2, 2); z1 = z1 + 1; //正确 //z1 = 1 + z1;//错误 }

    上述代码中,z1+1被解析为z.operator(1),他引起调用重载运算符的是左操作数z1,右操作数1通过Complex类型参数调用类的构造函数Complex(int a )建立临时对象执行函数。 但1+z1被解析为系统预定义版本时,z1无法装换成基本类型,而是被解析为重载版本: 1.operator+(z1),但整型值1不是Complex的对象,无法驱动函数运行。在此成员函数重载的+运算符不具备交换性。 因此,可以用友元函数重载运算符,左右参数都由参数传递,则C++语言通过构造函数实现数据的隐式转换。 既重载形式为:friend Complex operator+(Complex,Complex) 则上述问题得以解决。

    #include<iostream> using namespace std; class Complex { public: Complex(double r = 0, double i = 0) { Real = r; Image = i; } Complex(int a) { Real = a; Image = 0; } void print() const; friend Complex operator+ (const Complex & c1, const Complex & c2); friend Complex operator- (const Complex & c1, const Complex & c2); friend Complex operator- (const Complex & c); private: double Real, Image; }; Complex operator + (const Complex & c1, const Complex & c2) { double r = c1.Real + c2.Real; double i = c1.Image + c2.Image; return Complex(r, i); } Complex operator - (const Complex & c1, const Complex & c2) { double r = c1.Real - c2.Real; double i = c1.Image - c2.Image; return Complex(r, i); } Complex operator- (const Complex & c) { return Complex(-c.Real, -c.Image); } void Complex::print() const { cout << '(' << Real << " , " << Image << ')' << endl; } int main() { Complex c1(2.5, 3.7), c2(4.2, 6.5); Complex c; c = c1 - c2; // operator-(c1,c2) c.print(); c = 25 + c2; // operator+(25,c2) c.print(); c = c2 + 25; // operator+(c2,52) c.print(); c = -c1; // operator-(c1) c.print(); }

    如果希望运算符操作数(尤其第一个)有隐式转换,则重载运算符必须用友元函数(或则普通函数)。

    最新回复(0)