当前位置: 首页 > article >正文

运算符重载(关键字operator的使用)

1:运算符重载的方法

运算符重载的方法有三种,一种是将运算符重载函数写在类中,作为类的成员函数;另一种是将运算符重载函数写在类外,当该函数需要访问类的私有或者受保护成员时,在类中将该函数声明为友元函数;第三种是将运算符重载函数写在类外,且该函数不需要访问类的私有或受保护成员,则该函数是普通函数。

主要讲和类相关的运算符重载。

重载为成员函数

在类中重载运算符的格式是

函数类型 operator $(形式参数表){..........}

$代表被重载的运算符

看下面日期类的运算符重载

class Date
{
public:
	// 获取某年某月的天数
	int GetMonthDay(int year, int month);
	// 全缺省的构造函数
	Date(int year = 1900, int month = 1, int day = 1) :_year(year), _month(month), _day(day) {};
	// 拷贝构造函数
  // d2(d1)
	Date(const Date& d);
	// 赋值运算符重载
  // d2 = d3 -> d2.operator=(&d2, d3)
	Date& operator=(const Date& d);
	// 析构函数
	~Date();
	// 日期+=天数
	Date& operator+=(int day);
	// 日期+天数
	Date operator+(int day);
	// 日期-天数
	Date operator-(int day);
	// 日期-=天数
	Date& operator-=(int day);
	// 前置++
	Date& operator++();
	// 后置++
	Date operator++(int);
	// 后置--
	Date operator--(int);
	// 前置--
	Date& operator--();
	// >运算符重载
	bool operator>(const Date& d);
	// ==运算符重载
	bool operator==(const Date& d);
	// >=运算符重载
	bool operator >= (const Date& d);
	// <运算符重载
	bool operator < (const Date& d);
	// <=运算符重载
	bool operator <= (const Date& d);
	// !=运算符重载
	bool operator != (const Date& d);
    // 日期-日期 返回天数
	int operator-(const Date& d)const;
private:
	int _year;
	int _month;
	int _day;
};

上面函数我们只是在类中声明了运算符的重载还没有具体实现,我们在另外一个文件中对运算符的重载进行定义

int Date::GetMonthDay(int year, int month)
{
	assert(_month <= 12 &&_month>=1);
	static int arr[13] = { -1,31,28,31,30,31,30,31,31,30,31,30,31};
	if (month == 2 && (year % 4 == 0 && year % 100 != 0 ) || (year % 400 == 0))
	{
		return 29;
	}
	return arr[month];
}
Date::Date(const Date& d)
{
	_year = d._year;
	_month = d._month;
	_day = d._day;
}

Date& Date::operator=(const Date& d)
{
	this->_year = d._year;
	this->_month = d._month;
	this->_day = d._day;
	return *this;
}
Date::~Date()
{
	_year = _month = _day = 0;
}
Date& Date::operator+=(int day)
{
	_day += day;
	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);
		_month++;
		if (_month == 13)
		{
			_year++;
			_month = 1;
		}	
	}
	return *this;
}

Date Date::operator+(int day)
{
	Date tmp(*this);
	tmp += day;
	return tmp;
}

Date& Date::operator-=(int day)
{
	_day -= day;
	while (_day <= 0)
	{
		_day += GetMonthDay(_year, _month);
		_month--;
		if (_month == 0)
		{
			_month = 12;
			_year--;
		}
	}
	return *this;
}

Date Date::operator-(int day)
{
	Date tmp(*this);
	tmp -= day;
	return tmp;
}

Date& Date::operator++()
{
	*this += 1;
	return *this;
}

Date Date::operator++(int)
{
	Date tmp(*this);
	*this += 1;
	return tmp;
}

Date Date::operator--(int)
{
	Date tmp(*this);
	*this += 1;
	return tmp;
}

Date& Date::operator--()
{
	*this -= 1;
	return *this;
}


bool Date::operator>(const Date& d)
{
	if (_year > d._year)
	{
		return true;
	}
	else if (_year == d._year)
	{
		if (_month > d._month)
		{
			return true;
		}
		else if (_month == d._month)
		{
			return _day > d._day;
		}
	}
	return false;
}

bool Date::operator==(const Date& d)
{
	return _year == d._year && _month == d._month && _day == d._day;
}

bool Date::operator >= (const Date& d)
{
	return *this > d || *this == d;
}

bool Date::operator < (const Date& d)
{
	return !(*this >= d);
}

bool Date::operator <= (const Date& d)
{
	return *this < d || *this == d;
}

bool Date::operator != (const Date& d)
{
	return !(*this == d);
}

int Date::operator-(const Date& d)const
{
	Date max(*this);
	Date min(d);
	int flag = 1;
	if (max < min)
	{
		Date tmp = max;
		max = min;
		min = tmp;
		flag = -1;
	}
	int n = 0;
	while (min != max)
	{
		min++;
		n++;
	}
	return n * flag;
}

2:运算符重载规则

1:当运算符被⽤于类类型的对象时,C++语⾔允许我们通过运算符重载的形式指定新的含义。C++规定类类型对象使⽤运算符时,必须转换成调⽤对应运算符重载,若没有对应的运算符重载,则会编译报错。
2:运算符重载是具有特殊名字的函数,他的名字是由operator和后⾯要定义的运算符共同构成。和其他函数⼀样,它也具有其返回类型和参数列表以及函数体。
3:重载运算符函数的参数个数和该运算符作⽤的运算对象数量⼀样多。⼀元运算符有⼀个参数,⼆元运算符有两个参数,⼆元运算符的左侧运算对象传给第⼀个参数,右侧运算对象传给第⼆个参数。
4:如果⼀个重载运算符函数是成员函数,则它的第⼀个运算对象默认传给隐式的this指针,因此运算符重载作为成员函数时,参数⽐运算对象少⼀个。
5:运算符重载以后,其优先级和结合性与对应的内置类型运算符保持⼀致。
6:不能通过连接语法中没有的符号来创建新的操作符:⽐如operator@。
7:.* :: sizeof ? : .注意以上5个运算符不能重载。(选择题⾥⾯常考,⼤家要记⼀) 操作符⾄少有⼀个类类型参数,不能通过运算符重载改变内置类型对象的含义,如: intoperator+(int x, int y)
8:⼀个类需要重载哪些运算符,是看哪些运算符重载后有意义,⽐如Date类重载operator - 就有意义,但是重载operator + 就没有意义。
9:重载++运算符时,有前置++和后置++,运算符重载函数名都是operator++,⽆法很好的区分。
10:C++规定,后置++重载时,增加⼀个int形参,跟前置++构成函数重载,⽅便区分。
11:重载 << 和 >> 时,需要重载为全局函数,因为重载为成员函数,this指针默认抢占了第⼀个形参位置,第⼀个形参位置是左侧运算对象,调⽤时就变成了 对象 << cout,不符合使⽤习惯和可读性。重载为全局函数把ostream / istream放到第⼀个形参位置就可以了,第⼆个形参位置当类类型对象。

3:日期类中没有的运算符重载

我们在日期类中重载了单目运算符,关系运算符,逻辑运算符,赋值运算符的重载。我们现在来说明一下其他运算符的重载

1:位运算符的重载

class Array {
public:
	Array(int d[], int nn)
	{
		_n = nn;
		_data = new int[_n];
		for (int i = 0; i < _n; i++)
		{
			_data[i] = d[i];
		}
	}

	~Array()
	{
		if (_data != nullptr)
		{
			delete[] _data;
		}
	}
	void show()
	{
		for (int i = 0; i < _n; i++)
		{
			cout << _data[i] << " ";
		}
		cout << endl;
	}
	Array& operator<<(int num)
	{
		int tmp;
		for (int pass = 1; pass <= num; pass++)
		{
			tmp = _data[0];
			for (int i = 0; i < _n - 1; i++)
			{
				_data[i] = _data[i + 1];
			}
			_data[_n - 1] = tmp;
		}
		return *this;
	}
	
private:
	int* _data, _n;
};

int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9 };
	Array a(arr, sizeof(arr) / sizeof(arr[0]));
	a.show();
	a << 578;
	a.show();
	return 0;
}

我们将位运算符重载成了,可以直接对数组进行左移多少位。

2:下标访问运算符的重载

	int& operator[](int index)
	{
		if (index >= 0 && index < _n - 1)
		{
			return _data[index];
		}
		else
		{
			cout << "下标超出范围" << endl;
			exit(1);
		}
	}

我们依然使用上面的数组代码,定义和声明都在类中不做分离。

3:输入输出流的重载

我给出两种方法

1:使用友元
#define _CRT_SECURE_NO_WARNINGS 
#include<iostream>
using namespace std;

class Array {
    friend std::ostream& operator<< (std::ostream& out, const Array& data);
public:
    Array(int d[], int nn)
    {
        _n = nn;
        _data = new int[_n];
        for (int i = 0; i < _n; i++)
        {
            _data[i] = d[i];
        }
    }
    ~Array()
    {
        if (_data != nullptr)
        {
            delete[] _data;
        }
    }
    int& operator[](int index)
    {
        if (index >= 0 && index < _n)
        {
            return _data[index];
        }
        else
        {
            cout << "下标超出范围" << endl;
            exit(1);
        }
    }
private:
    int* _data;
    int _n;
};

std::ostream& operator<<(std::ostream& out, const Array& data)
{
    for (int i = 0; i < data._n; i++) {
        out << data._data[i] << " ";
    }
    return out;
}

int main()
{
    int arr[] = { 1,2,3,4,5,6,7,8,9 };
    Array a(arr, sizeof(arr) / sizeof(arr[0]));
    cout << a << endl;
    a[1] = 99;
    cout << a << endl;
    return 0;
}
2:定义两个接口
#define _CRT_SECURE_NO_WARNINGS 
#include<iostream>
using namespace std;

class Array {
public:
    Array(int d[], int nn)
    {
        _n = nn;
        _data = new int[_n];
        for (int i = 0; i < _n; i++)
        {
            _data[i] = d[i];
        }
    }
    ~Array()
    {
        if (_data != nullptr)
        {
            delete[] _data;
        }
    }
    int& operator[](int index)
    {
        if (index >= 0 && index < _n)
        {
            return _data[index];
        }
        else
        {
            cout << "下标超出范围" << endl;
            exit(1);
        }
    }
    const int* data() const
    {
        return _data;
    }
    int size() const
    {
        return _n;
    }
private:
    int* _data;
    int _n;
};

std::ostream& operator<<(std::ostream& out, const Array& data)
{
    for (int i = 0; i < data.size(); i++)
    {
        out << data.data()[i] << " ";
    }
    return out;
}

int main()
{
    int arr[] = { 1,2,3,4,5,6,7,8,9 };
    Array a(arr, sizeof(arr) / sizeof(arr[0]));
    cout << a << endl;
    a[1] = 99;
    cout << a << endl;
    return 0;
}


http://www.kler.cn/a/597675.html

相关文章:

  • 【STM32单片机】#2 GPIO输出
  • 鼠标拖拽实现DIV尺寸修改效果实现
  • 零基础本地部署 ComfyUI+Flux.1 模型!5 分钟搭建远程 AI 绘图服务器(保姆级教程)
  • 六西格玛遇上Python:统计学的高效实践场
  • 基于SpringBoot的图书借阅小程序+LW参考示例
  • Matplotlib完全指南:数据可视化从入门到实战
  • upload-labs靶场学习记录2
  • 再学:区块链基础与合约初探 EVM与GAS机制
  • java开发接口中,响应速度率成倍数提高的方法与策略
  • 基于BClinux8部署Ceph 19.2(squid)集群
  • SQL——创建临时表方法总结
  • 城市街拍人像自拍电影风格Lr调色教程,手机滤镜PS+Lightroom预设下载!
  • Opencv计算机视觉编程攻略-第一节 图像读取与基本处理
  • 百度SEO和必应SEO优化方法
  • 【css酷炫效果】纯CSS实现科技感网格背景
  • JVM运行时数据区内部结构难记?一个例子优化记忆
  • 摄影工作室预约管理系统基于Spring BootSSM
  • 校园自习室预约小程序(源码+部署教程)
  • 基于Spring Boot的健身房管理系统的设计与实现(LW+源码+讲解)
  • python网络爬虫开发实战之网页数据的解析提取