C++学习 十四、类的进阶(2)运算符重载

前言

本篇继续C++类的进阶学习,运算符重载。

运算符重载与函数重载

C++中,函数重载使同一函数名根据不同的参数列表实现不同的功能。

运算符重载与函数重载类似,使同一运算符对于不同类型的操作数实现特定的功能。

运算符重载实际上也是由函数重载实现的,本质上是函数重载。

运算符重载

关键字operator用于重载运算符。

运算符重载格式为:返回类型 operator 运算符名称 (参数列表) {}

注意:重载运算符的参数列表中,必须有一个参数类型是自定义类或者结构或者枚举类型

运算符重载,类方法

类内重载的运算符将成为类方法。

下面是一个重载+实现两数组相加的例子:

#include <cstdio>
#include <iostream>

class easyClass{
    private:
        int arr[5] {1,2,3,4,5};
    public:
        void operator+ (const easyClass);
};

void easyClass::operator+ (const easyClass ec){
    for(int i=0; i<5; i++)
    {
        arr[i] += ec.arr[i];
        std::cout << arr[i] <<std::endl;
    }
}

int main()
{  
    easyClass a;
    easyClass b;
    a + b;

  	return 1;
}

easyClass内重载了加法运算符+,是从左向右结合的运算符。在编译时,+左侧的操作数是一个类的对象,因此将使用类内重载的+

a.operator+(b);

也就是说,对于类内运算符重载,a + b实际上是对象a调用类方法+,对象b作为参数。

void easyClass::operator+ (const easyClass)的参数列表隐藏了调用对象自身,实际上是通过this指针传递了调用对象。
在这里插入图片描述
在这里插入图片描述
运算符重载需要遵循以下规则:

  • 必须有一个参数类型为自定义类,结果或者枚举;
  • 不能重载不存在的运算符;
  • 不能改变运算符本身的操作方式,操作数,结合顺序,优先级;
  • 部分运算符不能重载,包括sizeof().::?:等;

运算符重载,友元

类内重载运算符使其成为了类方法。但是,这里会出现一个操作数顺序问题,如下所示:

class A{
	private:
		int a_ {1};
	public:
		int operator* (int); 
};

int A::operator* (int x){
	return a_ + x;
}

void main(){
	A a;
	a * 2;
	2 * a; // error! 
}

A重载了*,因此a*2将被转换为a.operator*(2)

2*a将报error: no match for 'operator*' (operand types are 'int' and 'A'),因为类方法必须通过对象才能调用。

为了解决上面这个顺序问题,重载的运算符不能是类方法,但又要能够访问类的私有成员。因此,可以定义友元重载运算符,如下所示:

class A{
	private:
		int a_ {1};
	public:
		int operator* (int); 
		friend int operator* (int, A);
};

int A::operator* (int x){
	return a_ * x;
}

int operator* (int x, A a){
	return a.a_ * x;
}

void main(){
	A a;
	a * 2;
	2 * a;
}

编译器将2 * a替换为operator*(2, a)

注意:在类内通过friend关键字声明重载的运算符是友元类型,在类外定义时不能使用friend关键字。

注意:重载运算符时,必须注意类方法与友元函数可能出现的二义性问题,例如形参为对象时,就可能发生冲突:

class A{
	private:
		int a_ {1};
	public:
		int operator* (A); // redefinition
		friend int operator* (A, A); // redefinition
};

另外,如果已经在类内重载了运算符,则不需要友元函数也能够解决操作数顺序问题,示例如下:

class A{
	private:
		int a_ {1};
	public:
		int operator* (int); 
};

int A::operator* (int x){
	return a_ * x;
}

int operator* (int x, A a){
	return a * x;
}

void main(){
	A a;
	a * 2;
	2 * a;
}

由于类方法限定了重载运算符只能由对象调用,即首操作数必须为对象,那么在全局再重载一次该运算符,该运算符内正确调用类内重载的运算符即可。

<< 运算符的重载

为一个类重载<<运算符,更便于cout输出。

通常,重载<<应当使用友元函数,因为<<的调用对象通常是ostream类型的cout对象;此外,返回类型也应当是ostream &,这样能够连续输出流:

class A{
	private:
		int a_ {1};
	public:
        friend std::ostream& operator<< (std::ostream& os, const A&);
};

std::ostream& operator<< (std::ostream& os, const A& a) {
    os << a.a_ << " OK!" << std::endl;
    return os;
}

int main(){
	A a;
    std::cout << a;

    return 1; 
}

后记

本篇学习了运算符重载,下一篇将继续类的进阶学习,类的自动转换和强制转换。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值