一、友元函数的运算符重载
定义和用途
友元函数用于运算符重载时,可以访问类的私有和保护成员。这在一些情况下非常有用,特别是当需要访问多个类的私有成员时。例如,实现两个类对象之间的加法运算,或者实现全局运算符函数。
语法和实现
友元函数的运算符重载通常包括以下几个步骤:
- 在类声明中声明友元函数。
- 在类外部定义友元函数,实现具体的运算符重载逻辑。
二、实现步骤
假设我们有一个 Vector
类,代表二维向量,其中包括两个私有成员 x
和 y
。我们希望实现向量的加法操作,并使用友元函数对加法运算符进行重载。
-
定义
Vector
类:定义一个Vector
类,其中包括两个私有成员x
和y
,以及一个友元函数的声明。class Vector { private: double x, y; public: // 构造函数 Vector(double x = 0, double y = 0) : x(x), y(y) {} // 友元函数声明 friend Vector operator+(const Vector& v1, const Vector& v2); // 打印向量 void print() const { cout << "(" << x << ", " << y << ")" << endl; } };
-
声明友元函数:在
Vector
类中声明一个友元函数,以便该函数可以访问Vector
类的私有成员。这里我们将声明一个友元函数operator+
,用于重载+
运算符。// 友元函数声明 friend Vector operator+(const Vector& v1, const Vector& v2);
-
定义友元函数:在
Vector
类外部定义友元函数,实现对+
运算符的重载操作。在该函数中,我们需要访问Vector
类的私有成员,因此使用了友元函数。// 友元函数定义,用于重载+运算符 Vector operator+(const Vector& v1, const Vector& v2) { return Vector(v1.x + v2.x, v1.y + v2.y); }
三、使用友元函数重载的优点
访问私有成员:友元函数可以访问类的私有成员和保护成员。在某些情况下,需要在类外部定义函数来操作类的私有成员。使用友元函数可以方便地实现对私有成员的访问,从而进行运算符重载。
多个类之间的操作:有时候,运算符重载涉及多个类之间的操作。例如,实现两个类的对象之间的加法运算。此时,可以使用一个类的友元函数来访问另一个类的私有成员,以便进行运算。
增强封装性:虽然友元函数可以访问类的私有成员,但它们不是类的成员函数。因此,使用友元函数可以提供一定程度的封装性,避免将所有操作都作为类的成员函数公开。
提高灵活性:有时候,通过友元函数对运算符进行重载可以提高代码的灵活性和可读性。可以将某些与类相关但不属于类成员函数的操作定义为友元函数,使得代码更清晰。
四、代码示例
重载前置单目运算符 ‘--’
#include <iostream>
using namespace std;
class Counter {
private:
int value;
public:
// 构造函数
Counter(int v = 0) : value(v) {}
// 友元函数声明
friend Counter& operator--(Counter& c); // 前置递减
// 打印值
void print() const {
cout << value << endl;
}
};
// 友元函数定义,用于重载前置递减运算符
Counter& operator--(Counter& c) {
--c.value;
return c;
}
int main() {
Counter c(5);
--c; // 使用重载的前置递减运算符
cout << "c after --c: ";
c.print();
return 0;
}
重载后置单目运算符 ‘--’
#include <iostream>
using namespace std;
class Counter {
private:
int value;
public:
// 构造函数
Counter(int v = 0) : value(v) {}
// 友元函数声明
friend Counter operator--(Counter& c, int); // 后置递减
// 打印值
void print() const {
cout << value << endl;
}
};
// 友元函数定义,用于重载后置递减运算符
Counter operator--(Counter& c, int) {
Counter temp = c;
c.value--;
return temp;
}
int main() {
Counter c(5);
Counter c_old = c--; // 使用重载的后置递减运算符
cout << "c after c--: ";
c.print();
cout << "old c: ";
c_old.print();
return 0;
}
小结:由于友元运算符重载函数没有this指针,所以不能引用this指针所指的对象。使用友元函数重载自增运算符‘++’或自减运算符‘--’时,应采用对象引用参数传递数据。例如:
friend Three operator++(Three &);//前缀方式friend Three operator++(Three &,int);//后缀方式
重载双目运算符‘+’
#include <iostream>
using namespace std;
class Vector {
private:
double x;
double y;
public:
// 构造函数
Vector(double x = 0, double y = 0) : x(x), y(y) {}
// 友元函数声明
friend Vector operator+(const Vector& v1, const Vector& v2);
// 打印向量
void print() const {
cout << "(" << x << ", " << y << ")" << endl;
}
};
// 友元函数定义,用于重载+运算符
Vector operator+(const Vector& v1, const Vector& v2) {
return Vector(v1.x + v2.x, v1.y + v2.y);
}
int main() {
Vector v1(1, 2);
Vector v2(3, 4);
Vector v3 = v1 + v2;
cout << "v1: ";
v1.print();
cout << "v2: ";
v2.print();
cout << "v1 + v2: ";
v3.print();
return 0;
}
在进行双目运算符重载时,由于友元函数不使用this指针,故其参数列表中需要将两个参数都写上,例如
friend Complex operator+(Complex& a,Complex& b);
重载赋值运算符‘=’
赋值运算符重载必须作为成员函数,因为:
- 赋值运算符需要修改左操作数的内部状态。
- 友元函数无法访问隐式的
this
指针,也就无法直接操作对象自身的成员变量。因此,尽管友元函数可以访问类的私有成员变量和函数,但在涉及修改对象本身的情况下(例如赋值操作),必须使用成员函数来进行重载。