【C++/C】【学习笔记】重载!operator关键字背后的秘密~

一、重载的意义

在面向对象编程时,常常会建立一个类,例如建立一个矩形类,想判断其中两个对象(我声明的两个矩形)相等,则必须有长相等、宽相等;如果要写一个函数来进行比较,会不如我们常用的“==”运算符直观简单:

class rectangle{
private:
	int length, width; 
public:
	rectangle(int l, int w){
            length = l;
	    width = w;
	}
	bool IsSame(const rectangle&);		//比较函数 
	bool operator==(const rectangle&);	//重载"=="运算符 
};

bool rectangle::IsSame(const rectangle& a){
	if(length==a.length&&width==a.width){
	    return true;
	}
	else return false;
}

bool rectangle::operator==(const rectangle& a){
	if(length==a.length&&width==a.width){
	    return true;
	}
	else return false;
}

int main(){
	rectangle A(5,5);
	rectangle B(5,5);
	if(A.IsSame(B)){
	    cout<<"Same"<<endl;
	}
	if(A==B){				//符合语言习惯 更为直观 
	    cout<<"Same~"<<endl;
	}
	return 0;
}

所以,这个使得“==”运算符能被用户定义的类使用的过程就是“重载”。


二、重载的要求

1.不能改变运算符的初始意义。
2.不能改变运算符的参数数目。如重载运算符+时只用一个操作数是错误的。
3.运算符函数不能包括缺省的参数。
4.绝大部分C++运算符都可以重载,以下的例外: .   ::   .*   ?
5.除赋值运算符外,其它运算符函数都可以由派生类继承。
6.运算符重载不改变运算符的优先级和结合性,也不改变运算符的语法结构,即单目、双目运算符只能重载为单目、双目运算符。
7.运算符的重载实际上是函数的重载。编译程序对运算符重载的选择,遵循函数重载的选择原则。当遇到不很明显的运算符时,编译程序将去寻找参数匹配的运算符函数。
8.运算符重载可使程序更简洁,使表达式更直观,增强可读性。但使用不宜过多。
9.重载运算符含义必须清楚

(来源于网络)


三、重载的形式
可以将操作符重载为 成员函数形式友元函数形式
(1) 一般情况下,单目运算符最好重载为类的成员函数;双目运算符则最好重载为类的友元函数。
(2) 以下双目运算符不能重载为类的友元函数:=、()、[]、->。
(3) 类型转换函数只能定义为一个类的成员函数而不能定义为类的友元函数。
(4) 若一个运算符的操作需要修改对象的状态,选择重载为成员函数较好。
(5) 若运算符所需的操作数(尤其是第一个操作数)希望有隐式类型转换,则只能选用友元函数。
(6) 当运算符函数是一个成员函数时,最左边的操作数(或者只有最左边的操作数)必须是运算符类的一 个类对象(或者是对该类对象的引用)。如果左边的操作数必须是一个不同类的对象,或者是一个内部 类型的对象,该运算符函数必须作为一个友元函数来实现。
(7) 当需要重载运算符具有可交换性时,选择重载为友元函数。
(来源于网络)
对此,我个人有一种自己的理解:
考虑操作符重载为哪种形式时,可以从该操作符的“ 使用者”层面上来思考,
比如常见的“=”、“+=”、“*=”、“--”、“++”等,使用者都是“对象”,由“对象”来“使用”,所以定义为类的成员函数。(如上“==”的重载)

其他操作符如“+”、“-”、“*”、“/”、“%”的“使用者”应该是其两边的内容,所以定义为友元函数,赋予其访问私有成员的权利即可。

举个栗子 Int 是一个模拟整形的类:

bool operator ==(const Int&a) {
	if (i == a.i) return true;
	else return false;
}
void operator +=(const Int&a) {
	i += a.i;
}
/*类成员*/
/*友元函数*/
friend double operator*(const double a, const Int& e) {
	double c;
	c = a * e.i;
	return c;
}
friend double operator*(const Int& e, const double a) {
	double c;
	c = e.i * a;
	return c;
}
friend int operator*(const int a, const Int& e) {
	int c;
	c = a * e.i;
	return c;
}
friend int operator*(const Int& e, const int a) {
	int c;
	c = e.i*a;
	return c;
}
friend int operator*(const Int& e, const Int& a) {
	int c;
	c = e.i*a.i;
	return c;
}

四、输入输出流重载

继续以此段代码为例,重载输入输出 ">>" "<<" ,详见代码:

#include<iostream>
using namespace std;

class rectangle{
private:
	int length, width; 
public:
	rectangle(int l, int w){
	    length = l;
	    width = w;
	}
	friend istream &operator>>(istream &in, rectangle &a);//重载输入流
	friend ostream &operator<<(ostream &os, rectangle &a);//重载输出流
};

istream &operator>>(istream &in, rectangle &a){
	in >> a.length >> a.width;
	return in;
}

ostream &operator<<(ostream &os, rectangle &a){
	os << a.length << endl << a.width << endl;
	return os;
}
	

int main(){
	rectangle A(5,5);
	rectangle B(5,5);
	
	cin >> A;
	cout << A;
	cout << B;

	return 0;
}


五、类型转换运算符重载函数
这一点对于operator关键字的运用,除非查询时就输入这“生僻”的名称:“类型转换运算符重载函数“ 或者 ”类型转换函数“,否则并不容易查找到相关的资料…
详见 http://en.cppreference.com/w/cpp/language/cast_operator
简单地说,即是在类的内部声明
operator 类型名( )
{
     实现转换的语句
}

如代码所示:

#include<iostream>
using namespace std;

class rectangle{
private:
	int length, width; 
public:
	rectangle(int l, int w){
	    length = l;
            width = w;
	}
	operator int() const{
	    return length*width;
	}
};

istream &operator>>(istream &in, rectangle &a){
	in >> a.length >> a.width;
	return in;
}

ostream &operator<<(ostream &os, rectangle &a){
	os << a.length << " " << a.width << endl;
	return os;
}
	

int main(){
	rectangle A(5,5);
	rectangle B(5,5);
	
	int area = A;
	cout << area << endl;
	
	int area2;
	area2 = area + B;
	cout << area2 << endl;
	
	return 0;
}

以上拙见浅薄,如有谬误还望大犇们批评指正!

//Szp 2018.4.11



发布了30 篇原创文章 · 获赞 7 · 访问量 4435

猜你喜欢

转载自blog.csdn.net/weixin_40005329/article/details/79895623
今日推荐