【C++】运算符重载

一、运算符重载基础

1.语法

运算符重载函数的语法:返回值 operator 运算符 (参数列表)。
运算符重载函数的返回值与运算符本身的含义一致。

2.优点

C++将运算符重载扩展到自定义的数据类型,它可以让对象操作更加美观。
例如:字符串string用(+)拼接、cout用两个小于号(<<)输出。

3.种类

1) 非成员函数版本的重载运算符函数:形参个数与运算符需要操作的个数相同。

#include <iostream>
using namespace std;

class supman
{
	friend void operator+(supman& boy, int num);
	friend int main();
public:
	string m_name;
	supman()
	{
		m_name.clear(); m_score = 0;
		cout << "调用了supman()构造函数" << endl;
	}
private:
	int m_score;
	void show()  //自我介绍
	{
		m_name = "小马哥";
		cout << " m_name:" << m_name << "    " << "m_age:" << m_score << endl;
	}
};

void operator+(supman& boy,int num)
{
	boy.m_score = boy.m_score + num;
}

int main()
{
	supman boy;
	boy + 20;
	boy.show();
}

运行结果如下:

调用了supman()构造函数
 m_name:小马哥    m_age:20

C:\code\day\x64\Debug\day.exe (进程 37272)已退出,代码为 0。
按任意键关闭此窗口. . .

分析:先创建类supman的对象boy,执行默认构造函数,之后调用重载运算符函数。

2) 成员函数版本的重载运算符函数:形参个数比运算符的操作个数少一个,其中一个操作数隐式传递了调用对象。

#include <iostream>
using namespace std;

class supman
{
	friend int main();
public:
	string m_name;
	supman()
	{
		m_name.clear(); m_score = 0;
		cout << "调用了supman()构造函数" << endl;
	}
	supman& operator+(int num)  //成员函数版本的重载运算符函数,在类中对象的引用相当于自己this,可以省略。
	{
		m_score = m_score + num;
		return *this;
	}
private:
	int m_score;
	void show()  //自我介绍
	{
		m_name = "小马哥";
		cout << " m_name:" << m_name << "    " << "m_age:" << m_score << endl;
	}
};

int main()
{
	supman boy;
	boy + 20+10;
	boy.show();
}

运行结果如下:

调用了supman()构造函数
 m_name:小马哥    m_age:30

C:\code\day\x64\Debug\day.exe (进程 10980)已退出,代码为 0。
按任意键关闭此窗口. . .

如果同时重载了非成员函数和成员函数两个版本,就会导致二义性,出现编译错误。

4.注意细节

  • 返回自定义数据类型的引用可以让多个运算符表达式串联起来。(不要返回局部变量的引用) 例如boy+20+10;
  • 重载函数的函数列表决定了操作数的位置,也就是实参与形参的数据类型应一一对应;
  • 重载函数的参数列表中至少有一个是用户自定义的类型,防止程序员为内置数据类型重载运算符;
  • 如果运算符重载既可以是成员函数也可以是全局变量,应该优先考虑成员函数,这样更符合运算符重载的初衷;
  • 重载函数不能违背运算符原来的含义和优先级;
  • 不能创建新的运算符。

二、重载关系运算符

重载关系运算符(==、>=、<=、!=、>、<)用于比较两个自定义数据类型的大小。
可以使用非成员函数和成员函数两种版本,建议采用成员函数版本。

例:

#include <iostream>
using namespace std;

class supman
{
public:
	string m_name;
	int m_score;
	int m_grade;
	int m_level;
	supman(string name, int score, int grade, int level) :m_name(name), m_score(score), m_grade(grade), m_level(level) 
	{}
	bool operator == (const supman& man)
	{
		if ((m_score + m_grade + m_level) == (man.m_score + man.m_grade + man.m_level))
			return true; return false;
	}
	bool operator > (const supman & man)
	{
		if ((m_score + m_grade + m_level) > (man.m_score + man.m_grade + man.m_level))
			return true; return false;
	}
	bool operator < (const supman & man)
	{
		if ((m_score + m_grade + m_level) < (man.m_score + man.m_grade + man.m_level))
			return false; return true;
	}
};

int main()
{
	supman boy1("小马哥", 87, 65, 88);
	supman boy2("小雷哥", 86, 97, 83);
	if (boy1 == boy2) cout << "两位小哥平分秋色" << endl;
	else if (boy1 > boy2) cout << "小马哥一马当先" << endl;
	else cout << "小雷哥su7碉堡了" << endl;
}

运行结果如下:

小雷哥su7碉堡了

C:\code\day\x64\Debug\day.exe (进程 22048)已退出,代码为 0。
按任意键关闭此窗口. . .

三、重载左移运算符

重载左移运算符(<<)用于输出自定义对象的成员变量,在实际开发中很有价值(调试和日志)。
只能使用非成员函数版本。
如果输出对象的私有成员,可以配合友元一起使用。

1.简介

如果对象中有数组,重载下标运算符[],操作对象中的数组就像操作普通函数一样方便。
下标运算符[]必须以成员函数的形式进行重载。

2.语法

下标运算符重载函数的语法:
返回值类型 & operator[] (参数) ; 或 const 返回值类型 &operator[] (参数) const;
1)使用第一种声明方式,[]不仅可以访问数组元素,还可以修改数组元素;

#include <iostream>
using namespace std;

class supman
{
public:
	string m_name[3];
	int m_score;
	supman()
	{
		m_name[0] = "小马哥  "; m_name[1] = "小雷哥  "; m_name[2] = "小王哥";
	}
	void show()
	{
		cout << m_name[0] << m_name[1] << m_name[2] << endl;
	}
	string & operator[](int i)
	{
		return m_name[i];
	}
};

int main()
{
	supman boy;
	boy.m_name[1] = "小军哥  ";  //对第二个元素进行修改
	boy[1];
	boy.show();
}

运行结果如下:

小马哥  小军哥  小王哥

C:\code\day\x64\Debug\day.exe (进程 9828)已退出,代码为 0。
按任意键关闭此窗口. . .

2)使用第二种声明方式,[]只能访问而不能修改数组元素。

#include <iostream>
using namespace std;

class supman
{
public:
	string m_name[3];
	int m_score;
	supman()
	{
		m_name[0] = "小马哥  "; m_name[1] = "小雷哥  "; m_name[2] = "小王哥";
	}
	void show()  const //由于对象boy为const
	{
		cout << m_name[0] << m_name[1] << m_name[2] << endl;
	}
	const string & operator[](int i) const 
	{
		return m_name[i];
	}
};

int main()
{
	const supman boy;
	boy[1];
	boy.show();
}

运行结果如下:

小马哥  小雷哥  小王哥

C:\code\day\x64\Debug\day.exe (进程 23020)已退出,代码为 0。
按任意键关闭此窗口. . .

在实际开发中,我们应该同时提供以上两种形式,这样做是为了适应const对象,因为通过const对象只能调用const成员函数,如果不提供第二种形式,那么将无法访问const对象的任何数据元素。
在重载函数中,可以对下标做合法性检查,防止数组越界。

四、重载赋值运算符

C++编译器可能会给出类添加四个函数:

  • 默认构造函数,空实现;
  • 默认析构函数,空实现;
  • 默认拷贝构造函数,对成员变量进行浅拷贝;
  • 默认赋值函数,对成员变量进行浅拷贝。

1.定义

对象的赋值运算是用一个已经存在的对象,给另一个已经存在的对象赋值。
如果类的定义中没有重载赋值函数,编译器就会提供一个默认赋值函数。反之,编译器将不再提供默认赋值函数。

2.语法

重载赋值函数的语法:类名 & operator = (const 类名 & 源对象)。

3.注意

  • 编译器提供的默认赋值函数,是浅拷贝。
  • 如果对象中不存在堆区内存空间,默认赋值函数可以满足需求,是否需要深拷贝。
  • 赋值运算和拷贝构造不同:拷贝构造是指原来的对象不存在,用已存在的对象进行构造,赋值运算是指已经存在了两个对象,把其中一个对象的成员变量的值赋给另一个对象的成员变量。

五、重载new、delete运算符

重载new和delete运算符的主要目的是为了自定义内存分配的细节。(内存池:快速分配和归还,无碎片)

1.编译器的工作

在C++中,使用new时,编译器做了两件事情:
1) 调用标准库函数operator new()分配内存;
2) 调用构造函数初始化内存。
使用delete时,也做了两件事情:
1)调用析构函数;
2)调用标准库函数operator delete()释放内存。

2.重载函数

构造函数和析构函数由编译器调用,我们无法控制。但是,可以重载内存分配函数operator new()和释放函数operator delete()。
1)重载内存分配函数的语法:void* operator new(size_t size);
参数必须是size_t,返回值必须是void*。
2)重载内存释放函数的语法:void operator delete(void* ptr)
参数必须是void* (指向由operator new()分配的内存),返回值必须是void。
注意:

  • 重载的new和delete可以是全局函数,也可以是类的成员函数。
  • 为一个类创建new和delete时,尽管不必显示的使用static,但实际上仍在创建static成员函数。
  • 编译器看到使用new创建自定义的类的对象时,它选择成员版本的operator new()而不是全局版本的new()。
  • new[]和delete[]也可以重载。

六、重载括号运算符

括号运算符()也可以重载,对象名可以当成函数来使用(函数对象、仿函数)。

1.语法

括号运算符重载函数的语法:返回值类型 operator()(参数列表)

2.注意事项

  • 括号运算符必须以成员函数的形式进行重载;
  • 括号运算符重载函数具备普通函数全部的特征;
  • 如果函数对象与全局函数同名,按作用域规则选择调用的函数。

3.函数对象的用途

1)表面像函数,部分场景中可以替代函数,在STL中得到广泛的应用;
2)函数对象本质是类,可以用成员变量存放更多的信息;
3)函数对象有自己的数据类型;
4)可以提供继承体系。

七、重载一元运算符

1.种类

可重载的一元运算符
1)++自增 2)-- 自减 3)!逻辑非 4)& 取地址
5)~ 二进制反码 6)* 解引用 7)+ 一元加 8)- 一元求反
一元运算符通常出现在它们所操作的对象的左边。
但是,自增运算符++和自减运算符–有前置和后置之分。
C++规定,重载++或–时,如果重载函数有一个int形参,编译器处理后置表达式时,将调用这个重载函数。

2.语法

成员函数版:supman & operator++(); //++前置
成员函数版:supman operator++(int); //后置++
非成员函数版:supman & operator++(supman &); //++前置
非成员函数版:supman operator++(supman &,int); //后置++

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值