C++类和对象:运行符重载、取地址运算符重载、const 修饰的类如何作为参数

引言

介绍:C++类和对象:运行符重载、取地址运算符重载、const 修饰的类如何作为参数

涂色-博主主页

C++基础专栏

一、运算符重载

• 当运算符被用于类类型的对象时,C++语言允许我们通过运算符重载的形式指定新的含义。C++规定 类 类型对象使用运算符时,必须转换成调用对应运算符重载,若没有对应的运算符重载,则会编译报错。

• 运算符重载是具有特殊名字的函数,他的名字是由operator和后面要定义的运算符共同构成。和其他函数⼀样,它也具有其返回类型和参数列表以及函数体。

• 重载运算符函数的参数个数和该运算符作用的运算对象数量一样多。一元运算符有一个参数,而二元运算符有两个参数,二元运算符的左侧运算对象传给第一个参数,右侧运算对象传给第二个参数。

• 如果一个重载运算符函数是成员函数,则它的第一个运算对象默认传给隐式的this指针,因此运算符重载作为成员函数时,参数比运算对象少⼀个。

• 运算符重载以后,其优先级和结合性与对应的内置类型运算符保持⼀致。

cpp 复制代码
#include<iostream>
using namespace std;

class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1)
	{
		cout << "Date(int year = 1, int month = 1, int day = 1)";
		_year = year;
		_month = month;
		_day = day;
	}

 1、提供Getxxx函数
 2、友元
 3、直接放到类里面
//这里先使用第3点,前两点后面会讲
	bool operator==(const Date& d)
	{
		return _year == d._year
			&& _month == d._month
			&& _day == d._day;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d3(2025, 1, 1);
	Date d4(2025, 2, 2);
	cout << (d3 == d4) << endl;
	cout << d3.operator==(d4) << endl;
	return 0;
}

• 不能通过连接语法中没有的符号来创建新的操作符:比如operator@。

• .* :: sizeof ?: . 注意以上5个运算符不能重载。(选择题里面常考)

对 .* 操作符的理解

C++中规定:取类里面函数的地址的时候,要在函数名前加上&符号。函数指针需要声明类域

cpp 复制代码
#include<iostream>
using namespace std;

void Fun()
{
	cout << "Fun()" << endl;
}
class A
{
public:
	void func()
	{
		cout << "A::func()" << endl;
	}
};

void f()
{
	cout << "f()" << endl;
}
int main()
{
	//正常函数指针
	void(*func1)() = Fun;
	func1();
	//类里面的函数指针:
	void(A:: * func2)() = &A::func;
	A aa;
	(aa.*func2)(); //这里会使用 .* 符号。
}

• 重载操作符至少有⼀个类类型参数,不能通过运算符重载改变内置类型对象的含义,如: operator+(int x, int y)

• 一个类需要重载哪些运算符,是看哪些运算符重载后有意义,比如Date类重载operator-就有意 义,但是重载operator+就没有意义。

• 重载++运算符时,有前置++和后置++,运算符重载函数名都是operator++,无法很好的区分。 C++规定,后置++重载时,增加一个int形参,跟前置++构成函数重载,方便区分。

• 重载 << 和 >> 时,需要重载为全局函数,因为重载为成员函数,this指针默认抢占了第一个形参位置,第一个形参位置是左侧运算对象,调用时就变成了对象 <<cout,不符合使用习惯和可读性。重载为全局函数把ostream/istream放到第一个形参位置就可以了,第二个形参位置当前类类型对象。

二、赋值运算符重载

赋值运算符重载是一个默认成员函数,用于完成两个已经存在的对象直接的拷贝赋值,这里要注意跟拷贝构造区分,拷贝构造用于一个对象拷贝初始化给另一个要创建的对象。

赋值运算符重载的特点:

1. 赋值运算符重载是一个运算符重载,规定必须重载为成员函数。赋值运算重载的参数建议写成 const 当前类类型引用,否则会传值传参会有拷贝。

2. 有返回值,且建议写成当前类类型引用,引用返回可以提高效率,有返回值目的是为了支持连续赋值场景。

3. 没有显式实现时,编译器会自动生成一个默认赋值运算符重载,默认赋值运算符重载行为跟默认拷贝构造函数类似,对内置类型成员变量会完成值拷贝 / 浅拷贝(一个字节一个字节的拷贝),对自定义类型成员变量会调用他的赋值重载函数。

4.像Date这样的类成员变量全是内置类型且没有指向什么资源,编译器自动生成的赋值运算符重载就可以完成需要的拷贝,所以不需要我们显示实现赋值运算符重载。像Stack这样的类,虽然也都是 内置类型,但是_a指向了资源,编译器自动生成的赋值运算符重载完成的值拷贝 / 浅拷贝不符合我们的需求,所以需要我们自己实现深拷贝 (对指向的资源也进行拷贝)。像MyQueue这样的类型内部主要是自定义类型Stack成员,编译器自动生成的赋值运算符重载会调用Stack的赋值运算符重载, 也不需要我们显示实现MyQueue的赋值运算符重载。

这里还有一个小技巧,如果一个类显示实现了析构并释放资源,那么他就需要显示写赋值运算符重载,否则就不需要。

cpp 复制代码
#include<iostream>
using namespace std;


class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1)
	{
		cout << "Date(int year = 1, int month = 1, int day = 1)" << endl;

		_year = year;
		_month = month;
		_day = day;
	}

	bool operator==(const Date& d)
	{
		return _year == d._year
			&& _month == d._month
			&& _day == d._day;
	}
	Date& operator=(const Date& d)
	{
		//不需要自己给自己赋值
		if (this != &d)
		{
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}
		return *this;
	}
	void print()
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1(2025, 1, 1);
	Date d2(2025, 2, 2);
	d2 = d1;
	d1.print();
	d2.print();
}

三、const 修饰的类如何作为参数

const成员函数

• 将 const 修饰的成员函数称之为 const 成员函数,const 修饰成员函数放到成员函数参数列表的后面。

• const 实际修饰该成员函数隐含的 this 指针,表明在该成员函数中不能对类的任何成员进行修改。 如:const 修饰 Date类的Print成员函数,Print隐含的this指针由 Date* const this 变为:const Date* const this

不想对类里面的内容改变,就在函数后面加上const修饰。

cpp 复制代码
#include<iostream>
using namespace std;

class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	// void Print(const Date* const this) const
	void Print() const
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
const
int main()
{
	// 这⾥⾮const对象也可以调⽤const成员函数是⼀种权限的缩⼩
	Date d1(2024, 7, 5);
	d1.Print();
	const Date d2(2024, 8, 5);
	d2.Print();
	return 0;
}

四、取地址运算符重载

取地址运算符重载分为普通取地址运算符重载和const取地址运算符重载,⼀般这两个函数编译器自动生成的就可以够我们用了,不需要去显示实现。除非一些很特殊的场景,比如我们不想让别人取到当前类对象的地址,就可以自己实现一份,胡乱返回⼀个地址。

cpp 复制代码
class Date
{
public:
	Date* operator&()
	{
		//return this;
		 return nullptr;
	}
	const Date* operator&()const
	{
		//return this;
		return nullptr;
	}
private:
	int _year; // 年
	int _month; // ⽉
	int _day; // ⽇
};
相关推荐
程序员阿鹏1 分钟前
Git的安装和配置(idea中配置Git)
java·开发语言·ide·git·intellij-idea·idea
景天科技苑13 分钟前
【Rust trait特质】如何在Rust中使用trait特质,全面解析与应用实战
开发语言·后端·rust·trait·rust trait·rust特质
PacosonSWJTU17 分钟前
python使用matplotlib画图
开发语言·python·matplotlib
Rachelhi22 分钟前
C++.神经网络与深度学习(赶工版)(会二次修改)
c++·深度学习·神经网络
Inverse16223 分钟前
C语言_自定义类型:结构体
c语言·开发语言·算法
enyp8031 分钟前
Qt原型模式实现与应用
开发语言·qt·原型模式
理论最高的吻1 小时前
77. 组合【 力扣(LeetCode) 】
c++·算法·leetcode·深度优先·剪枝·回溯法
CryptoRzz1 小时前
印度尼西亚数据源对接技术指南
开发语言·python·websocket·金融·区块链
zyx没烦恼1 小时前
unordered_map和unordered的介绍和使用
开发语言·c++
LuckyRich11 小时前
【RabbitMq C++】消息队列组件
c++·分布式·rabbitmq