一、操作符函数的概念:
在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;
}
注意:运算符的重载要符合情理。
全局函数
可能会访问到参数的私有成员:
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++语言给我们提供了重载运算符的功能,但是这其实是一种锦上添花的技术,我们要合理的使用这个功能,不能随心所欲,否则会出现一些不可预测的错误,合理使用,会为我们的程序增加可读性,和方便。