C++可以通过运算符重载来完成用户定义类型的运算。具体语法就是把函数名换成operator@,其中@代表特定的运算符。
#include<iostream>
#include<cstdio>
using namespace std;
class NODE
{
private:
int x, y;
public:
NODE(int _x = 0, int _y = 0)
{
x = _x;
y = _y;
}
NODE operator+(NODE &a) const; //对+重载
NODE operator-(NODE &a) const; //对-重载
};
NODE NODE::operator+(NODE &a) const
{
NODE t;
t.x = this->x + a.x;
t.y = this->y + a.y;
return t;
}
NODE NODE::operator-(NODE &a) const
{
NODE t;
t.x = this->x - a.x;
t.y = this->y - a.y;
return t;
}
int main()
{
NODE a(1, 1), b(2, 2);
NODE add, sub, mul;
add = a + b; //相当于调用a.operator+(b)
sub = a - b; //相当于调用a.operator-(b)
return 0;
}
现在对*进行重载,让类和一个int类型的数据相乘。
NODE operator*(int x); //函数原型
NODE NODE::operator*(int x) //函数定义
{
NODE t;
t.x = this->x*x;
t.y = this->y*x;
return t;
}
当遇到a*b时(a是NODE类型,b是int类型),将转换成a.operator*(b)来调用。
但如果遇到b*a呢,会转换成b.operator*(a),但实际上并没有这个函数原型,因此会报错。
C++提供友元函数来解决这个问题
友元函数
通过让函数成为类的友元,可以赋予该函数与类的成员函数相同的访问权限。即类的友元函数可以方位类的私有成员。因此,友元函数不是类的成员函数,它是一般函数,但是它能访问类的私有成员。
创建友元函数的第一步是在类中声明它的原型,代表它是该类的友元函数,需要关键字friend。
第二步就是编写函数定义,在类外编写。因为它不是成员函数,因此不需要加类名来限定。
#include<iostream>
#include<cstdio>
using namespace std;
class NODE
{
private:
int x, y;
public:
NODE(int _x = 0, int _y = 0)
{
x = _x;
y = _y;
}
NODE operator+(NODE &a) const; //对+重载
NODE operator-(NODE &a) const; //对-重载
NODE operator*(int x);
friend NODE operator*(int x, NODE &a);
};
NODE operator*(int x, NODE &a)
{
NODE t; //这4行完全可以换成 return a*x; 相当于调用a.operator(x)
t.x = x*a.x;
t.y = x*a.y;
return t;
}
NODE NODE::operator*(int x)
{
NODE t;
t.x = this->x*x;
t.y = this->y*x;
return t;
}
NODE NODE::operator+(NODE &a) const
{
NODE t;
t.x = this->x + a.x;
t.y = this->y + a.y;
return t;
}
NODE NODE::operator-(NODE &a) const
{
NODE t;
t.x = this->x - a.x;
t.y = this->y - a.y;
return t;
}
int main()
{
NODE a(1, 1), b(2, 2);
NODE add, sub, mul;
add = a + b; //这里调用的是a.operator+(b)
sub = a - b; //这里调用的是a.operator-(b)
mul = a * 1; //这里调用的是a.operator(1)
mul = 1 * a; //这里调用的operator*(1,a)
return 0;
}
另外还可以重载运算符<<,来输出用户定义的类。即cout<<a。其中,a是某个类的对象。cout是ostream对象,能识别所有C++基本类型。因为对于基本类型,ostream类声明中都包含了相应的重载的operator<<()的定义。我们也可以重载<<来输出自己定义的类。
因为cout<<a。可以看出是双目运算符,cout作为第一个参数,a作为第二个参数。因此不能通过类的成员函数进行重载,因为那样子会默认类对象是第一个参数(这和上面1*a是一样道理)。因此只能作为友元函数进行重载。
第一个版本:
#include<iostream>
#include<cstdio>
using namespace std;
class NODE
{
private:
int x, y;
public:
NODE(int _x = 0, int _y = 0)
{
x = _x;
y = _y;
}
friend void operator<<(ostream &os, NODE &a);
};
void operator<<(ostream &os, NODE &a)
{
os << a.x << " " << a.y << endl;
}
int main()
{
NODE t;
cout << t;
return 0;
}
但是还有一个问题,这个版本无法处理类似cout<<a<<b;的情况。
先看常规的cin>>x>>y;这里x和y都是基本类型。C++从左至右输出语句,所以它等价于 (cout<<x)<<y; 因为在ostream类中的operator<<重载,返回的依然是ostream类的引用,且该引用就是传进去的参数cout。因此cout<<x最终将返回cout,该cout再用来输出y。
因此要修改成如下
#include<iostream>
#include<cstdio>
using namespace std;
class NODE
{
private:
int x, y;
public:
NODE(int _x = 0, int _y = 0)
{
x = _x;
y = _y;
}
friend ostream& operator<<(ostream &os, NODE &a);
};
ostream& operator<<(ostream &os, NODE &a)
{
os << a.x << " " << a.y << endl;
return os;
}
int main()
{
NODE t, a(1, 1);
cout << t << a;
return 0;
}
另外,ofstream对象可以用于输出写入到文件,通过继承,ofstream可以使用ostream的方法。类继承属性让ostream引用可以指向ostream对象和ofstream对象。因此还可以通过该重载来将输出写入文件
ofstream fout;
fout.open("a.txt");
fout << t; //将调用operator<<(fout,t);