【C++】之类和对象 - 运算符重载

目录

一.赋值运算符重载

二.前置/后置++运算符重载

三.流输入/输出重载

四.取地址/const取地址重载


前言:

运算符重载与函数重载没有本质上的关系

运算符重载:让自定义类型对象可以用运算符,转换成调用重载函数

函数重载:支持函数名相同的函数存在

.*   ::   sizeof   ?:   .  以上五个运算符不可以重载,笔试题经常出现!

一.赋值运算符重载

C++为了增强代码可读性,增加了运算符的重载,运算符重载是具有特殊函数名的函数

关键字:operator

语法:operator + 要重载的运算符

3 + 3 = 6,如果是日期 + 日期呢,加法运算符就不能直接使用了。在C语言中,我们可以写一个日期加法函数,然后再调用这个函数,将两个日期以参数的形式传递进去;在C++中,为了使代码更具有可读性,增加了一个特性就是操作符可以被重载,本质就是可以自己显式定义一下操作符函数,与内置的发生重载。

用赋值运算符重载举例:

#include<iostream>
using namespace std;

class Date
{
public:
	//构造函数
	Date(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
		cout << "调用构造" << endl;
	}
	//日期类赋值运算符重载
	Date& operator=(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
		cout << "调用重载" << endl;
		return *this; 
	}
	//打印日期
	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1(0,0,0);//这里会调用构造函数 因为这是初始化
	Date d2(2022, 8, 9);
	cout << "-----------------------------------------------" << endl;
	d1 = d2;//这里会调用赋值运算符重载
	cout << "-----------------------------------------------" << endl;
	d1.Print();
	return 0;
}

赋值运算符重载后,看似d1 = d2是直接使用的

本质是:如果在类内重载的话,等价于d1.operator=(d2);

              如果在类外重载的话,等价于operator=(d1,d2);d1是左操作数,d2是右操作数

赋值运算符的返回值可以起到“链式编程”的作用,例如d4 = d1 + d2 + d3;

赋值运算符只能在类内重载,不能在全局重载

原因:如果我们不显式的定义赋值运算符重载,编译器会默认生成,如果我们在全局重载的话,在调用时,例如d1=d2,会引发歧义,这时编译器不知道应该调用哪一个。

编译器默认生成(类内):Date& operator(const Date& d) 

全局显式定义:Date& operator(Date& d1, const Date& d2)

有人会问这两个参数不是不同吗?别忘了编译器在类内生成的成员函数是有this指针的,也就是Date& this。

但其实不让我们在全局显式定义赋值运算符的重载只是编译器的强制行为,因为d1=d2这样调用会有二义性,但是如果d1.operator=(d2)这样就会调用类内的,operator=(d1,d2)这样就会调用全局的。

总结:

1.如果不写赋值运算符重载,编译器会在类内生成一个

2.不能在全局写赋值运算符的重载(编译器强制行为),如d1 = d2,调用会发生二义性

3.编译器默认生成的赋值运算符重载对于内置类型值拷贝(浅拷贝),对于自定义类型调用其自己的赋值运算符重载

二.前置/后置++运算符重载

规定:前置运算符重载没有参数,后置运算符重载有一个int占位参数

在类内或全局都可以重载

(这里为了重点展示运算符重载对于日期准确性不做要求)

1.前置++运算符重载(日期类类内实现)

Date& operator++()
{
	_day++;
	return *this;
}

2.后置++运算符重载(日期类类外实现)

Date operator++(Date& d, int)
{
	Date copy = d;
	d._day++;
	return d;
}

整体代码:

#include<iostream>
using namespace std;

class Date
{
	friend Date operator++(Date& d, int);

public:

	Date(int year, int month, int day)
		:_year(year), _month(month), _day(day)
	{

	}
	//这里为了重点展示运算符重载对于日期准确性不做要求
	
	//前置++运算符重载
	Date& operator++()
	{
		_day++;
		cout << "前置++" << endl;
		return *this;
	}
private:
	int _year;
	int _month;
	int _day;
};

Date operator++(Date& d, int)
{
	Date copy = d;
	d._day++;
	cout << "后置++" << endl;
	return d;
}

int main()
{
	Date d1(2022, 8, 10);
	d1++;
	++d1;
	return 0;
}

三.流输入/输出重载

流输入/流输出运算符一定要在全局重载

因为如果在类内重载的话,加入实例化对象d1,那么调用函数一定是d1.operator<<(cout),这里d1与cout位置就反了,应该cout在左,d1在右,例如cout<<d1,所以在参数顺序固定的情况下,只能在全局重载

1.流输入重载

istream& operator>>(istream& in, Date& d)
{
	in >> d._year >> d._month >> d._day;
	return in;
}

2.流输出重载

ostream& operator<<(ostream& out, Date& d)
{
	out << d._year << "-" << d._month << "-" << d._day << endl;
	return out;
}

整体代码:

class Date
{
	friend istream& operator>>(istream& in, Date& d);
	friend ostream& operator<<(ostream& out, Date& d);

public:
	

private:
	int _year;
	int _month;
	int _day;
};

istream& operator>>(istream& in, Date& d)
{
	in >> d._year >> d._month >> d._day;
	return in;
}
ostream& operator<<(ostream& out, Date& d)
{
	out << d._year << "-" << d._month << "-" << d._day << endl;
	return out;
}
int main()
{
	Date d1;
	cout << "输入:年 月 日" << endl;
	cin >> d1;
	cout << "打印:年 月 日" << endl;
	cout << d1 << endl;
	return 0;
}

四.取地址/const取地址重载

当我们没写这两个运算符重载(一般不用写),系统默认生成

1.对普通变量取地址操作符的重载

2.对const变量取地址操作符的重载

class Date
{
public:
	Date(int year, int month, int day)
		:_year(year), _month(month), _day(day)
	{

	}
private:
	int _year;
	int _month;
	int _day;
};


int main()
{
	Date d1(2022, 8, 10);
	cout << &d1 << endl;
	const Date d2(2022, 8, 20);
	cout << &d2 << endl;
	return 0;
}

可以看到我们没写针对Date类的取地址,系统也没有报错

 本质:

1.对普通变量取地址操作符的重载

Date* operator&()
{
	return this;
}

2.对const变量取地址操作符的重载

const Date* operator&() const
{
	return this;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
为实现复数类的++ --运算,我们需要对复数类进行运算符重载。我们可以重载++和--运算符和后置++和--运算符。 下面是一个简单的复数类的定义: ```cpp class Complex { private: double real_; double imag_; public: Complex(double real = 0, double imag = 0) : real_(real), imag_(imag) {} double real() const { return real_; } double imag() const { return imag_; } Complex operator++(); //++ Complex operator--(); //置-- Complex operator++(int); //后置++ Complex operator--(int); //后置-- }; Complex Complex::operator++() { real_++; imag_++; return *this; } Complex Complex::operator--() { real_--; imag_--; return *this; } Complex Complex::operator++(int) { Complex temp(*this); real_++; imag_++; return temp; } Complex Complex::operator--(int) { Complex temp(*this); real_--; imag_--; return temp; } ``` ++和--运算符直接将实部和虚部分别加/减1即可。 后置++和--运算符需要先保存当对象的值,然后再将实部和虚部分别加/减1,最后返回保存的对象值。 下面是一个使用复数类的示例: ```cpp int main() { Complex a(1, 2); Complex b = ++a; Complex c = b--; cout << "a=" << a.real() << "+" << a.imag() << "i" << endl; cout << "b=" << b.real() << "+" << b.imag() << "i" << endl; cout << "c=" << c.real() << "+" << c.imag() << "i" << endl; return 0; } ``` 输出结果为: ``` a=2+3i b=2+3i c=3+4i ``` 可以看到,++和后置--运算符都可以正常工作。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值