运算符重载

在c++中我们可以使用

int a=10;
int b=20;
int c=a+b;

我们知道int类型相加即为将变量中的值相加,a+b=30;

这是由于编译器编译系统在内部重载了内置类型的加法运算,这种重载的实质是函数重载,即int operator+(int,int)但是编译系统只能对内置的类型进行函数重载。

那么如果变量的类型是类类型呢?

如:

#include<iostream>
using namespace std;


class CInt
{
public:
	CInt(int a) :ma(a){
	}
private:
	int ma;
};

int main()
{
CInt a;
CInt b;
CInt c=a+b;
return 0;
}

在上面的代码中,我们也要想实现类似int类型的相加,将对象a和对象b的成员变量相加。

编译器的重载只能对系统定义的基本数据类型起作用,对用户自己定义的数据类型无法提供相应的运算符重载形式。

这就必须我们手动实现这个函数,相当于对'+'号进行了重定义,实现CInt对象之间的相加。

运算符重载的方式就是定义一个函数,在函数体内实现想要的功能,当用到该运算符时,编译器就会自动调用这个函数。也就是说,运算符重载就是通过函数定义实现的,它本质上是函数重载。

运算符重载规则

1. 不可以重载的运算符

长度运算符(sizeof)、条件运算符(: ?)、成员选择符(.)、对象选择符(.*)、域解析符(::)、构造函数的成员初始化器(:)不能被重载

1. 不可以重载的运算符

 .* ::  ?:  sizeof

2.重载运算符的限制

不改变运算符的优先级

不改变运算符的结合性

不改变运算符所需要的操作数

不能创建新的运算符

3.运算符重载的语法形式

运算符函数定义的一般格式如下: 
   <返回类型说明符> operator <重载的运算符符号>(<参数表>) 
  {... 
   <函数体> 
  } 

 运算符重载为成员函数 

我们实现CInt类的'+' 运算符重载函数

CInt operator+(const CInt rhs)
{
  return CInt(this->ma+rhs.ma);
}

在上面的函数我们可以看出'+'需要两个操作数,但是由于类的成员函数中默认的this指针,系统默认将左操作数作为默认参数传递给this指针,所以我们只需要在形参列表中将右操作数传入。

我们知道在C语言中有前置++和后置++,按照运算符重载函数的定义都为 operator++();

为了区别这个函数是前置++还是后置++,我们在后置++的形参列表中添加一个整型参数加以区别,并无其他含义

前置++运算符重载函数

const CInt operator++(int)
{
	const CInt tmp(ma);
	ma++;
	return tmp;
}

后置++运算符重载函数

CInt& operator++()
{
	++ma;
	return *this;
}

在上面我们知道系统默认将双目运算符的左操作数传递给this指针,那么在重载[]运算符时

例如:

CInt arr[] = { 123, 123, 2, 4, 324, 23, 4 };
	
int len = sizeof(arr) / sizeof(arr[0]);
for (CInt i = 0;i < len; i++)
{
	CInt b=arr[i];
}

我们知道在arr[i]这个关系中,arr是左操作数,i是右操作数,按照规则我们将arr传递给this指针,可是arr并不是一个对象,

这个代码就会出现问题。

为了实现[]运算符的重载,我们在重载[]是将右操作数传递给this指针,而将左操作数通过形参带入

因为arr[i]=*(arr+i)=*(i+arr)=i[arr]

例如:

int& operator[](int* arr)
{
	return arr[ma];
}

当然我们也可以重载int 

例如:

operator int()
{
	return ma;
}

该函数的返回值类型就是函数名,所以不用显式地表示出。

什么叫返回类型就是函数名?
返回类型是int,函数名也是int,就是说不写成 int operator int()  { return ma; },
返回类型被省去了。

operator int() 是类型转换运算符,目的是把CInt类型的对象转换成int类型

在调用arr[i]时会调用arr[i.operatoe int()],此时i就已经转换成int类型,arr[i]也就可以编译通过

 运算符重载为友员函数 

友元函数声明 friend +函数原型

友员是单向的

例如:函数a是CInt类的友元函数,函数a中可以访问CInt类中的私有成员变量,但CInt类不能访问函数a中的变量。

不存在传递关系

例如:函数a是CInt类的友元函数,CInt类又是CDouble类的友员,但函数a与CDouble类之间不存在友员关系。

例如:

int a;

cin>>a;

cout<<a;

如果a的类型是CInt类型呢?

那我们必须重载'>>','<<'运算符

<<运算符的重载函数

ostream& operator<<(ostream& out, const CInt& rhs)
{
    out << rhs.ma;
    return out;
}

<<运算符的重载函数

istream& operator>>(istream& in, CInt& rhs)
{
    in >> rhs.ma;
    return in;
}

说明几点:

1.第一个形参为对ostream、istream对象的引用,在该对象上将产生输出,输入,ostream为非const,因为写入到流会改变流的状态;该形参是一个引用,因为不能复制ostream、istream对象(在c++中定义的标准输入输出流类istream和ostream,其中拷贝构造函数和赋值操作符函数都被放置在了private部分,且只有声明,没有定义)。

2.第二个形参一般应是对要输出的类类型的引用,该形参是一个引用以避免复制实参,减少一次拷贝。

3.返回类型是一个ostream、istream引用,它的值通常是输出操作符所操作的ostream、istream对象,首先因为ostream、istream对象不能复制,所以必须是引用;其次引用可以少一次拷贝,提高效率;最后,为了体现连续性,实现连续输出,达到用多个输出、输入操作符操作一个ostream、istream对象的效果,如果不是引用,程序返回的时候就会生成新的临时对象,也就是说,连续的两个<<操作符实际上是针对不同对象的,这就好比cout<<a<<b;与cout<<a; cout<<b;和cin>>a>>b 与cin>>a; cin>>b;的区别。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值