C++——运算符重载为成员函数与非成员函数的区别 – 作者:Johnson666

运算符重载为成员函数

运算符重载为成员函数可以使函数方便地访问本类的成员变量,调用时通过该类的某个对象来操作运算符重载函数。由于成员函数是类的一部分,调用成员函数会传递this指针,因此类对象自身即为一个参数。

加法运算为双目运算符,若用oprd1表示左操作数,oprd2表示右操作数,则oprd1为对象本身的数据,即由this指针指向对象的成员,而oprd2通过运算符重载函数的参数提供,表达式可以写成oprd1+oprd2,相当于函数调用oprd1.operator+(oprd2)。

单目运算符如取地址运算符(&)、指针运算符(*)、自增自减运算运算符(++、–)只有一个操作数,在重载为成员函数时则不需要参数。例如,用oprd表示操作数,进行前置自增运算时表达式可以写成++oprd,相当于函数调用oprd.operator++()。
自增自减运算分为前置和后置两类,因此为了区分前置和后置自增自减运算,C++做了如下约定:当重载后置自增自减运算符时,函数要带有一个整型的形参,该整型参数在运算中不起任何作用,只是作为区分前置与后置运算的标记。

前置自增运算符的重载

例子:

#include<iostream>
using namespace std;
class Integer
{
private:
	int value;

public:
	Integer(int num)  //定义构造函数
	{
		value = num;
	}
	Integer()  //重载构造函数
	{
		value = 0;
	}
	Integer operator++();  //声明前置自增运算符函数
	int setValue(int num)
	{
		value = num;
	}
	void display();  //声明输出函数
};

Integer Integer::operator++()  //定义前置自增运算符重载函数
{
	value++;  //相当于this->value++;
	return *this;
}

void Integer::display()  //定义输出函数
{
	cout << value << endl;
}

int main()
{
	Integer num(10);
	cout << "num=";
	num.display();
	++num;
	cout << "++num=";
	num.display();
	return 0;
}

结果:
image.png
本例中对Integer对象进行前置自增运算,调用运算符重载函数会先自增,再返回增加后的对象进行输出。

后置自增运算符的重载

如果采用后置自增运算,则调用运算符重载函数虽然仍然会对对象进行自增运算,但返回的是自增前的对象。
例子:

#include<iostream>
using namespace std;
class Integer
{
private:
	int value;

public:
	Integer(int num)  //定义构造函数
	{
		value = num;
	}
	Integer()  //重载构造函数
	{
		value = 0;
	}
	Integer operator ++();  //声明前置自增运算符函数
	Integer operator ++(int);  //声明后置自增运算符函数
	int setValue(int num)
	{
		value = num;
	}
	void display();  //声明输出函数
};

Integer Integer::operator ++()  //定义前置自增运算符重载函数
{
	value++;  //相当于this->value++;
	return *this;
}

Integer Integer::operator ++(int)  //定义后置自增运算符重载函数
{
	Integer temp = *this;
	value++;  //相当于this->value++;
	return temp;
}

void Integer::display()  //定义输出函数
{
	cout << value << endl;
}

int main()
{
	Integer num1(10),num2;
	cout << "num1=";
	num1.display();
	++num1;
	cout << "执行++num1;后:" << endl;
	cout << "num1=";
	num1.display();
	num2 = num1++;
	cout << "执行num2=num1++后:" << endl;
	cout << "num1=";
	num1.display();
	cout << "num2=";
	num2.display();
	return 0;
}

结果:
image.png

运算符重载为非成员函数

运算符重载函数作为成员函数所需的参数个数比原运算符所需参数个数少一个,因为其中一个操作数会隐式地传递给调用对象。

当运算符重载函数作为非成员函数时,运算所需的操作数都需要通过函数的参数来传递。仍以加法运算和自增运算为例,加分运算符重载为非成员函数,若用oprd1表示左操作数,oprd2表示右操作数,则表达式oprd1+oprd2相当于函数调用operator+(oprd1,oprd2)。

自增运算符重载为非成员函数,若用oprd表示该操作数,则前置自增运算时表达式++oprd相当于函数调用operator++(oprd),而后置自增运算时表达式oprd++相当于函数调用operator++(oprd,0)。

运算符重载函数作为友元函数

运算符重载函数作为非成员函数,可以声明为非友元函数,也可以声明为友元函数。若该函数只需要访问类中的公有部分的成员,则可以声明为非友元函数;若该函数需要访问运算符参数对象的私有成员,则声明为类的友元函数。由于两种声明方式处理过程相似,此处以声明为友元函数的情况进行说明。

例子:
有两个矩阵a和b,均为2行3列,求两矩阵之和。以非成员函数的形式重载运算符+,使之能用于矩阵相加。如c=a+b。

#include<iomanip>
#include<iostream.h>
class Matrix
{
private:
int mat[2][3];
public:
Matrix();
friend Matrix operator+(Matrix &a,Matrix &b);
void input();
void display();
};
Matrix::Matrix()
	  {
	  for(int i=0;i<2;i++)
		  for(int j=0;j<3;j++)
			  mat[i][j]=0;
	   }
Matrix operator+(Matrix &a,Matrix &b)  //定义运算符+重载函数
{
Matrix c;
for(int i=0;i<2;i++)
		  for(int j=0;j<3;j++)
			 c.mat[i][j]=a.mat[i][j]+b.mat[i][j];
		  return c;
}
void Matrix::input()
{
for(int i=0;i<2;i++)
		  for(int j=0;j<3;j++)
			  cin>>mat[i][j];
}
void Matrix::display()
{
for(int i=0;i<2;i++)
{
for(int j=0;j<3;j++)
cout<<mat[i][j]<<"  ";
cout<<endl;
}
}
int main()
{
Matrix a,b,c;
cout<<"input a:\n";
a.input();
cout<<"input b:\n";
b.input();
c=a+b;
cout<<"output c:\n";
c.display();
return 0;
}

结果:
image.png
上例中,将加法运算符重载为类的非成员函数,必须把两个矩阵对象都通过参数传递给运算符重载函数。将该函数声明为友元函数,保证了函数中矩阵对象可以访问类的私有成员变量。

重载流插入和流提取运算符

例子:

#include<iomanip>
#include<iostream>
using namespace std;

class Matrix
{
private:
int mat[2][3];
public:
Matrix();
friend Matrix operator+(Matrix &a,Matrix &b);
friend ostream& operator <<(ostream&,Matrix&);  //声明重载<<为友元函数
friend istream& operator >>(istream&,Matrix&);  //声明重载>>为友元函数
};

Matrix::Matrix()
	  {
	  for(int i=0;i<2;i++)
		  for(int j=0;j<3;j++)
			  mat[i][j]=0;
	   }

Matrix operator+(Matrix &a,Matrix &b)  //定义运算符+重载函数
{
Matrix c;
for(int i=0;i<2;i++)
		  for(int j=0;j<3;j++)
			 c.mat[i][j]=a.mat[i][j]+b.mat[i][j];
		  return c;
}

istream& operator >>(istream &in,Matrix &m)  //定义运算符>>重载函数
{
	for(int i=0;i<2;i++)
	for(int j=0;j<3;j++)
	in>>m.mat[i][j];
	return in;
}

ostream& operator <<(ostream &out,Matrix &m)  //定义运算符<<重载函数
{
for(int i=0;i<2;i++)
{
for(int j=0;j<3;j++)
out<<std::left<<setw(5)<<m.mat[i][j];
out<<endl;
}
return out;
}
int main()
{
Matrix a,b,c;
cout<<"input a:\n";  //相当于调用函数operator>>(cin,a);
cin>>a;
cout<<"input b:\n";  //相当于调用函数operator>>(cin,b);
cin>>b;
c=a+b;
cout<<"output c:\n";  //相当于调用函数operator<<(cout,c);
cout<<c;
return 0;
}

结果:
image.png
上例中,形参out和in分别是ostream和istream类的对象,是实参cout和cin的引用,也就是说out和in分别是cout和cin的别名,可以随意取名。因此,存在以下等价关系:
in>>m.mat[i][j]; <==> cin>>m.mat[i][j];
out<<m.mat[i][j]; <==> out<<m.mat[i][j];

来源:freebuf.com 2021-06-07 15:30:14 by: Johnson666

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论