在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;的区别。