运算符重载

概述

操作符重载是c++的重要特性之一,它允许我们以简单的方式操作对象,隐藏了内部机制。

操作符重载的基本形式为:[可选项] 返回值 operator运算符(可选参数列表) { 函数体 }

下面我们通过一个简单的例子来仔细讨论每一个部分。

一个简单的例子

我们先定义一个时间类,利用该类来说明操作符重载的方方面面。

// mytime.h
#pragma once

#include <iostream>

class Time
{
public:
	Time();
	Time(int h, int m = 0);
	~Time();
	void AddMin(int m);
	void AddHr(int h);
	void Reset(int h = 0, int m = 0);
	Time Sum(const Time& t) const;
	void Show() const;

    //作为成员函数重载的操作符
	Time operator+(const Time& t) const; // 1
	Time operator*(double m); // 2

    // 作为友元重载的操作符
	friend Time operator*(double m, const Time& t); // 3
	friend std::ostream& operator<<(std::ostream& os, const Time& t); // 4
private:
	int hours;
	int minutes;
};

我们重载了+、*以及<<操作符。其中+运算符作为类的成员函数重载(类的一部分),*运算符即有成员函数的重载版本,也有作为友元的重载版本(不是类的一部分),<<作为友元重载。

作为类成员函数的操作符重载

第一个和第二个重载就是作为类成员函数的重载,这时候的运算符与普通成员函数没有区别。来看第一个重载的实现:

Time Time::operator+(const Time& t) const
{
	return this->Sum(t);
}

此时的+是类的一部分,所以需要加上Time::。这个重载没有可选项,返回值是Time对象,参数是Time类型的引用。从实现中可以看到,我们在里面调用了具有相同功能的成员函数,这是操作符重载的常见写法。

定义好重载的操作符后,我们可以使用它:

Time t1(12,23), t2(4,12);
t1 = t1+t2;
//上述语句等价于:t1 = t1.operator+(t2);

t1 = t1 * 2;
//上述语句等价于调用:t1 = t1.operator*(2);

注意*操作符的调用,调用的是作为成员函数的操作符,而不是友元,如果我们把代码改成下面这样,就会调用友元版的操作符:

t1 = 2 * t1;
// 等价于调用:t1 = operator*(2, t1);

可以看到,对于作为成员函数的操作符,其参数比原操作符少一个。其实也可以这样理解,作为成员函数的操作符,第一个参数不是我们在代码中显式写出的那个,而是隐式传递的this指针。this对应操作符的左操作数,我们定义的参数对应操作符的右操作数。

作为友元的操作符重载

在上一节我们已经使用了*操作符的友元版本,这里给出*操作符的友元版本的实现:

Time Time::operator*(double m)
{
	Time t;

	t.minutes = this->minutes * m;
	t.hours = this->hours * m;
	t.hours += t.minutes / 60;
	t.minutes %= 60;

	return t;
}

此时的*是友元,而不是类的一部分,所以我们不需要加上Time::。接下来我们着重介绍<<运算符的重载。先给出它的实现:

std::ostream& operator<<(std::ostream& os, const Time& t)
{
	os << t.hours << " hours, " << t.minutes << " minutes";
}

它的第一个参数是一个流对象,第二个参数是用户自定义对象,分别对应<<运算符的左操作数和右操作数。它的返回值是流对象的引用,这样一来我们就可以写出如下的代码:

std::cout << t1 << std::endl;

这条语句的执行是从左到右的,调用的第一个<<返回了一个流对象,该流对象可以继续参与第二个<<的运算。

重载限制

重载的操作符不一定是成员函数,但是至少有一个操作数类型是用户自定义类型,这防止用户为标准类型重载运算符。

使用运算符不能违反运算符原来的语法规则,比如说不能将+重载为只有一个操作数的运算符。

// +t1;
// t1+;

不能修改运算符的优先级。

不能创建新的运算符。

不能重载以下运算符:

  • sizeof
  • .
  • .*
  • ::
  • ? :
  • typeid
  • 强制类型转换运算符

以下运算符只能通过成员函数进行重载:=,(),[],->

如果运算符表示的意思过于抽象或复杂,建议通过函数来实现,而不是重载运算符。

posted @ 2025-06-08 00:42  XueZhou  阅读(20)  评论(0)    收藏  举报