C++中的操作符函数(对操作符的重载)

一、操作符函数的概念:

     在C++中,编译器有能力把一个由数据、对象和操作符共同组成的表达式,解释为对一个全局或成员函数的调用。
  该全局或成员函数被称为操作符函数,通过重定义操作符函数,可以实现针对自定义类型的运算法则,并使之与内置类型一样参与各种表达式。

二、

双目操作符表达式
  成员函数 
    形如L#R双目操作符表达式,将被编译器解释为 L.operator#(R) 
    a-b+c == a.operator-(b).operator+(c)
  全局函数 
    形如L#R的双目操作符表达式,将被编译器解释为 ::operator#(L,R) 
    a-(b+c) == ::operator-(a,::operator+(b,c))

   来看一个例子:把赋值运算符重载的。

#include<iostream>
#include<stdlib.h>

using namespace std;
class Num
{

 	int a;
	int b;
public:
	Num(){}
	Num(int _a,int _b)
	{
		a=_a;
		b=_b;
	}

    Num& operator=(Num& num2)
    {
	a=num2.a;
	b=num2.b;
	return *this;
    }
}

这里其实也是类似赋值构造函数的写法,注意赋值运算符只能是重载为类成员,而无法重载为全局的。

三、单目操作符表达式
  成员函数 
    形如#O或O#的单目操作表达式,将被编译器解释为 O.operator#(),唯一的操作数是调用对象。
  全局函数 
    形如#O或O#的单目操作表达式,将被编译器解释为 ::operator#(O),唯一的操作数是调用对象。

四、典型的双目运算符重载
    成员函数
    Point operator /+-*%|^& (Point& that)
    {
        Point t; // 会调用无参构造
        t.x = x / that.x;
        t.y = y / that.y;
        return t; // 不能返回局部对象的引用,否则会出现悬空引用
    }
    注意:原对象的值不变,要产生一个临时的对象

    bool operator > < >= <= == != || && (Point& that)
    {
        
    }

    Point& operator += -= *= /=  (Point& that)
    {
    
        return *this;    
    }

    注意:运算符的重载要符合情理。

扫描二维码关注公众号,回复: 2652689 查看本文章

    全局函数
    可能会访问到参数的私有成员:
        1、把成员变成公开,但会破坏类的封闭性。
        2、把全局函数声明为友元(友元不是成员),
        3、不能在友元函数中直接访问成员变量。
    Point operator + (Point& a,Point& b)
    {
        Point t(a.x+b.x,a.y+b.y);
        return t;
    }

五、典型的单目运算符重载
    成员函数:
    前++/--    
    Point& operator ++/-- (void)
    {

    }

    后++/--
    Point operator ++/-- (int)
    {

    }

    全局函数:
    前++/--    
    Point& operator ++/-- (Point&)
    {

    }

    后++/--
    Point operator ++/-- (Point&,int)
    {

    }

六、输入、输出运算符重载
    输入、输出运算符不能重载为成员函数,只能是友元。
    ostream& operator << (ostream& os,Point& p)
    {

    }

    istream& operator >> (istream& is,Point& p)
    {

    }

七、特殊的运算符的重载
    [] 下标运算符,可以把对象当作数组来使用。
    () 函数运算符,可以把对象当作函数来使用。
    -> 成员访问运算符,可以把对象当作指针来使用。
    * 解引用运算符,可以把对象当作指针来使用。
    new/delete 也可以进行重载,但不建议使用。
        new会自动调用重载的new函数再构造函数。
        delete会先调用析构再调用重载的delete函数。

    只有极个别的运算符的重载对于对象来说是有意义(>>,<<)
        常考的运算符重载:前++/--,后++/--

八、运算符重载的一些限制
    1、不能重载的运算符
        :: 作用域限定符
        . 成员访问运算
        .* 成员指针解引用
        ?: 三目运算符
        sizeof 字节长度运算符
        typeid 类型信息操作符
    2、运算符的重载改变不了运算符的优先级
    3、无法改变运算符的操作个数
    4、无法发明新的运算符
    5、重载运算符要注意运算符的一致性
        不要改变运算符默认的运算规则
    6、运算符的重载是为了方便使用、增强可读,不应该成功卖弄的工具。

下面将以上的一些运算符的重载代码共享出来

#include<iostream>
#include<stdlib.h>

using namespace std;
class Num
{

 	int a;
	int b;
public:
	Num(){}
	Num(int _a,int _b)
	{
		a=_a;
		b=_b;
	}
/*
	Num operator-(Num &that)
	{
		Num n;
		n.a=a-that.a;
		n.b=b-that.b;
		return n;
	}
	Num operator+(Num &that)
	{
		Num n;
		n.a=a+that.a;
		n.b=b+that.b;
		return n;
	}
	Num operator*(Num &that)
	{
		Num n;
		n.a=a*that.a;
		n.b=b*that.b;
		return n;
	}
	Num operator/(Num &that)
	{
		Num n;
		n.a=a/that.a;
		n.b=b/that.b;
		return n;
	}
*/
/*
	Num& operator ++(void)//前++
	{
		a++;
		b++;
		return *this;
	}
	Num operator ++(int)//后++
	{
		Num n=*this;
		a++;
		b++;
		return n;
	}
	Num& operator --(void)//前--
	{
		a--;
		b--;
		return *this;
	}
	Num operator --(int)//后--
	{
		Num n=*this;
		a--;
		b--;
		return n;
	}
	*/
Num& operator=(Num& num2)
{
	a=num2.a;
	b=num2.b;
	return *this;
}
//friend Num& operator=(Num& num1,Num& num2)
friend Num operator --(Num& num);//前--
friend Num operator --(Num& num,int);//后--
friend Num operator/(Num& a,Num& b);
friend Num operator-(Num& a,Num& b);
friend Num operator*(Num& a,Num& b);
friend Num operator+(Num& a,Num& b);
friend Num operator+=(Num& num1,Num& num2);
friend istream& operator>>(istream& in,Num& n);//输入输出无法重载为成员函数
friend ostream& operator<<(ostream& out,Num& n);
Num* operator->(void)
{
	
	//a=that.a;
	//b=that.b;
	return this;
}
	void show(void)
	{
		cout<<a<<" "<<b<<endl;
	}
	//尽量不要使用
	/*void* operator new(unsigned int size)
	{
		return malloc(size);
	}*/
};
istream& operator>>(istream& in,Num& n)
{
	in>>n.a>>n.b;
	return in;
}
ostream& operator<<(ostream& out,Num& n)
{
	out<<"n.a="<<n.a<<" "<<"n.b"<<n.b;
	return out;
}
//Num n;
Num operator --(Num& num)//前--
{
	//Num n;
	num.a--;
	num.b--;
		
	return num;
}
Num operator --(Num& num,int)//后--
{
	Num n(num.a--,num.b--);
	return n;
}
Num operator+=(Num& num1,Num& num2)
{
	Num n;//会调用无参构造
	n.a=num1.a+num2.a;
	n.b=num1.b+num2.b;
	//cout<<n.b<<endl;
	return n;

}
Num operator/(Num& a,Num& b)
{
	//Num n;//会调用无参构造
	Num n(a.a/b.a,a.b/b.b);
	return n;
}
Num operator+(Num& a,Num& b)
{
	//Num n;//会调用无参构造
	Num n(a.a+b.a,a.b+b.b);
	return n;
}
Num operator-(Num& a,Num& b)
{
	//Num n;//会调用无参构造
	Num n(a.a-b.a,a.b-b.b);
	return n;
}
Num operator*(Num& a,Num& b)
{
	//Num n;//会调用无参构造
	Num n(a.a*b.a,a.b*b.b);
	return n;
}
int main()
{
	Num num1(3,7);
	Num num2(2,3);
	num1=num2;
	cout<<num1<<endl;
	//(num1--).show();
	//cin>>num1>>num2;
	//num1.show();
	//num2.show();
	//num1->show();
}

这里面包括了以上大部分的例子,我单独注释调试了!都是可以用的,friend 为友元函数,目的是在全局重载时,能访问到类中的私有成员。

最后利用重载来讲链表实现成数组的样子,即重载[]这个运算符!下面给出代码

#include<iostream>
using namespace std;

typedef int T;
struct Node
{
	T data;
	Node* next;
};
class List
{
private:
	Node* head;
	int lenth;
public:
	List();
	void inserthead(T data);//插入
	Node* getnode(int index);//获取节点
	bool insert(T data,int index);//插入指定位置
	bool remove(T data);//删除
	int list_lenth(void);//链表长度
	int find(T data);//查找
	void show(void);//显示链表
	T operator [](int i)//重载[]用i访问链表中的元素值
	{
		Node* node=head;
		while(node!=NULL)
		{
			if(i==0)
			{
				break;
			}
			i--;
			node=node->next;
		}
		return node->data;
	}

	~List();
	
};
List::List()
{
	head=new Node;
	head->next=NULL;
	lenth=0;
}
List::~List()
{
	Node* temp;
	for(int i=0;i<lenth;i++)
	{
		temp=head;
		head=head->next;
		delete temp;
	}
}
	
void List::inserthead(T data)
{
	Node* node=new Node;
	node->data=data;
	node->next=head->next;
	head->next=node;
	lenth++;
}
Node* List::getnode(int index)
{
	Node* node=new Node;
	node=head;
	for(int i=0;i<index;i++)
	{
		node=node->next;
	}
	return node;
}
bool List::insert(T data,int index)
{
	if(index<0||index>lenth)return false;
	Node* prevnode=getnode(index);
	Node* node=new Node;
	node->data=data;
	node->next=prevnode->next;
	prevnode->next=node;
	lenth++;
	return true;
}
bool List::remove(T data)
{
	int i=find(data);
	if(i==-1)return false;
	//cout<<i<<endl;
	Node* prevnode=getnode(i-1);
	//cout<<prevnode->data<<endl;
	Node* node=prevnode->next;
	//cout<<node->data<<endl;
	prevnode->next=node->next;
	delete node;
}
int List::list_lenth(void)
{
	return lenth;
}
int List::find(T data)
{
	Node* node=head;
	int index=0;
	while(node->next!=NULL)
	{
		if(node->data==data)
		{
			return index;
		}
		index++;
		node=node->next;
	}
	return -1;

}
void List::show(void)
{
	Node* node=head->next;
	while(node!=NULL)
	{
		cout<<node->data<<endl;
		node=node->next;
	}
}
ostream& operator<<(ostream& out,List& head)
{
	head.show();
	return out;
}//重载<<方便输出链表!
int main()
{
	List head;
	head.inserthead(5);
	head.inserthead(4);
	head.inserthead(3);
	//head.insert(6,3);
	//head.remove(4);
	//cout<<head.list_lenth();
	//head.show();
	cout<<head;

}

总结:虽然C++语言给我们提供了重载运算符的功能,但是这其实是一种锦上添花的技术,我们要合理的使用这个功能,不能随心所欲,否则会出现一些不可预测的错误,合理使用,会为我们的程序增加可读性,和方便。

猜你喜欢

转载自blog.csdn.net/Dachao0707/article/details/81542029
今日推荐