【C++】运算符重载案例 - 字符串类 ⑤ ( 重载 大于 > 运算符 | 重载 小于 < 运算符 | 重载 右移 >> 运算符 - 使用全局函数重载 | 代码示例 )

这篇具有很好参考价值的文章主要介绍了【C++】运算符重载案例 - 字符串类 ⑤ ( 重载 大于 > 运算符 | 重载 小于 < 运算符 | 重载 右移 >> 运算符 - 使用全局函数重载 | 代码示例 )。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。





一、重载 大于号 / 小于号 运算符 - 使用成员函数重载




1、重载 大于 > 运算符


使用 成员函数 实现 等于判断 == 运算符重载 :

  • 首先 , 写出函数名 , 函数名规则为 " operate " 后面跟上要重载的运算符 ,
    • 要对 String a , b 对象对比操作 , 使用 大于 > 运算符 , 使用时用法为 a > b ;
    • 函数名是 operate> ;
operate>
  • 然后 , 根据操作数 写出函数参数 , 参数一般都是 对象的引用 ;
    • 要对 String a , b 对象对比操作 , 使用 大于 > 运算符 , 使用时用法为 a > b ;
    • 左操作数 : 其中 左操作数 是 String a , 这里通过 this 指针调用 , 不需要声明在参数中 ;
    • 右操作数 : 右操作数 是 String b ; 该操作数需要声明在参数中 , 注意需要声明 引用类型 ;
    • 上述两个是对象类型 , 对象一般传入 指针 或 引用 , 这里传入引用类型 ;
operator>(String& s)
  • 再后 , 根据业务完善返回值 , 返回值可以是 引用 / 指针 / 元素 ;
    • 此处返回值是 bool 类型 , 返回 true 或者 false 布尔值即可 ;
bool operator>(String& s)
  • 最后 , 实现函数体 , 编写具体的运算符操作业务逻辑 ;
    • 将 String 类比较转为 字符串比较 ;
    • 使用 strcmp 函数进行 字符串比较 ;
// 重载 大于 > 运算符
bool String::operator>(String& s)
{
	// 将 String 类比较转为 字符串比较 
	// 大于 和 小于 区别是 参数顺序不同的区别
	return strcmp(this->m_p, s.m_p);
}

2、重载 小于 < 运算符


使用 成员函数 实现 小于 < 运算符重载 :

  • 首先 , 写出函数名 , 函数名规则为 " operate " 后面跟上要重载的运算符 ,
    • 要对 String a , b 对象对比操作 , 使用 小于 < 运算符 , 使用时用法为 a < b ;
    • 函数名是 operate< ;
operate<
  • 然后 , 根据操作数 写出函数参数 , 参数一般都是 对象的引用 ;
    • 要对 String a , b 对象对比操作 , 使用 小于 < 运算符 , 使用时用法为 a < b ;
    • 左操作数 : 其中 左操作数 是 String a , 这里通过 this 指针调用 , 不需要声明在参数中 ;
    • 右操作数 : 右操作数 是 String b ; 该操作数需要声明在参数中 , 注意需要声明 引用类型 ;
    • 上述两个是对象类型 , 对象一般传入 指针 或 引用 , 这里传入引用类型 ;
operator<(String& s)
  • 再后 , 根据业务完善返回值 , 返回值可以是 引用 / 指针 / 元素 ;
    • 此处返回值是 bool 类型 , 返回 true 或者 false 布尔值即可 ;
bool operator<(String& s)
  • 最后 , 实现函数体 , 编写具体的运算符操作业务逻辑 ;
    • 将 String 类比较转为 字符串比较 ;
    • 使用 strcmp 函数进行 字符串比较 ;
// 重载 小于 < 运算符
bool String::operator<(String& s)
{
	// 将 String 类比较转为 字符串比较
	// 大于 和 小于 区别是 参数顺序不同的区别
	return strcmp(s.m_p, this->m_p);
}




二、重载 右移 >> 运算符 - 使用全局函数重载



左移 << 操作符 cout << s << endl , 是将 s 对象输出到 cout 标准输出流中 ;

右移 >> 操作符 cin << s , 是将 标准输入流 cin 中的内容输入到 s 对象中 ;


使用 成员函数 实现 右移 >> 运算符 重载 :

  • 首先 , 写出函数名 , 函数名规则为 " operate " 后面跟上要重载的运算符 ,
    • 要对 String a , b 对象对比操作 , 使用 右移 >> 运算符 , 使用时用法为 a >> b ;
    • 函数名是 operate>> ;
operate>>
  • 然后 , 根据操作数 写出函数参数 , 参数一般都是 对象的引用 ;
    • 要对 String a , b 对象对比操作 , 使用 右移 >> 运算符 , 使用时用法为 a >> b ;
    • 左操作数 : 其中 左操作数 是 String a , 这里通过 this 指针调用 , 不需要声明在参数中 ;
    • 右操作数 : 右操作数 是 String b ; 该操作数需要声明在参数中 , 注意需要声明 引用类型 ;
    • 上述两个是对象类型 , 对象一般传入 指针 或 引用 , 这里传入引用类型 ;
operator>>(String& s)
  • 再后 , 根据业务完善返回值 , 返回值可以是 引用 / 指针 / 元素 ;
    • 此处返回值是 istream& , 返回引用类型 , 可以进行链式调用 ;
istream& operator>>(String& s)
  • 最后 , 实现函数体 , 编写具体的运算符操作业务逻辑 ;
// 全局函数 中实现 String 右移运算符重载
// 返回 istream& 引用类型 , 是为了支持链式调用 cin >> s1 >> endl;
istream& operator>>(istream& in, String& s)
{
	cin >> s.m_p;
	return in;
}

在 String 内部类中 , 将 上述 全局函数 声明为 String 的 友元函数 ;文章来源地址https://www.toymoban.com/news/detail-734012.html

	// 使用 全局函数 实现 右移运算符 >> 重载
	// 将全局函数 声明为 String 的友元函数
	friend istream& operator>>(istream& in, String& s);




三、完整代码示例




1、String.h 类头文件


#pragma once

#include "iostream"
using namespace std;

class String
{
public:
	// 默认的无参构造函数
	String();

	// 有参构造函数 , 接收一个 char* 类型字符串指针
	String(const char* p);

	// 有参构造函数 , 接收 int 类型值 , 表示字符串大小
	String(int len);

	// 拷贝构造函数 , 使用 String 对象初始化 对象值
	String(const String& s);

	// 析构函数
	~String();

public:
	// 重载等号 = 操作符 , 右操作数是 String 对象的情况
	String& operator=(const String& s);

	// 重载等号 = 操作符 , 右操作数是 字符串常量值 的情况
	String& operator=(const char* p);

	// 重载 数组下标 [] 操作符
	char& operator[](int i);

	// 重载 双等号 == 运算符
	bool operator==(String& s);

	// 重载 不等号 != 运算符
	bool operator!=(String& s);

	// 重载 大于 > 运算符
	bool operator>(String& s);

	// 重载 小于 < 运算符
	bool operator<(String& s);

	// 使用 全局函数 实现 左移运算符 << 重载
	// 将全局函数 声明为 String 的友元函数
	friend ostream& operator<<(ostream& out, String& s);

	// 使用 全局函数 实现 右移运算符 >> 重载
	// 将全局函数 声明为 String 的友元函数
	friend istream& operator>>(istream& in, String& s);

public:
	// 获取私有成员 char* m_p
	char* str();

	// 获取私有成员 int m_len
	int len();

private:
	// 字符串长度 , 不包括 '\0'
	// 内存占用空间大小 = 字符串长度 + 1
	int m_len;

	// 字符串指针, 指向堆内存中的字符串
	char* m_p;
};

2、String.cpp 类实现


// 使用 strcpy 函数报错
// error C4996: 'strcpy': This function or variable may be unsafe. 
// Consider using strcpy_s instead. 
// To disable deprecation, use _CRT_SECURE_NO_WARNINGS. 
// See online help for details.
#define _CRT_SECURE_NO_WARNINGS

#include "String.h"

// 默认的无参构造函数
String::String()
{
	// 默认构造一个空字符串 , 字符串长度为 0 
	// 但是 , 字符串指针 指向的内存空间大小是 1 , 内容是 '\0'
	m_len = 0;

	// 使用 new 关键字为 char* m_p; 指针分配内存
	// 对于基础数据类型 new 等同于 malloc
	m_p = new char[m_len + 1];

	// 拷贝空字符串到 m_p 指向的内存中
	strcpy(m_p, "");

	cout << "调用无参构造函数" << endl;
}

// 有参构造函数 , 接收一个 char* 类型字符串指针
String::String(const char* p)
{
	if (p == NULL)
	{
		// 默认构造一个空字符串 , 字符串长度为 0 
		// 但是 , 字符串指针 指向的内存空间大小是 1 , 内容是 '\0'
		this->m_len = 0;

		// 使用 new 关键字为 char* m_p; 指针分配内存
		// 对于基础数据类型 new 等同于 malloc
		this->m_p = new char[this->m_len + 1];

		// 拷贝空字符串到 m_p 指向的内存中
		strcpy(this->m_p, "");
	}
	else
	{
		// 获取传入字符串的长度
		// 但是 , 字符串指针 指向的内存空间大小需要 +1 , 内容是 '\0'
		this->m_len = strlen(p);

		// 使用 new 关键字为 char* m_p; 指针分配内存
		// 对于基础数据类型 new 等同于 malloc
		this->m_p = new char[this->m_len + 1];

		// 拷贝字符串到 m_p 指向的内存中
		strcpy(this->m_p, p);
	}
	cout << "调用有参构造函数" << endl;
}

// 有参构造函数 , 接收 int 类型值 , 表示字符串大小
String::String(int len)
{
	if (len == 0)
	{
		// 默认构造一个空字符串 , 字符串长度为 0 
		// 但是 , 字符串指针 指向的内存空间大小是 1 , 内容是 '\0'
		this->m_len = 0;

		// 使用 new 关键字为 char* m_p; 指针分配内存
		// 对于基础数据类型 new 等同于 malloc
		this->m_p = new char[this->m_len + 1];

		// 拷贝空字符串到 m_p 指向的内存中
		strcpy(this->m_p, "");
	}
	else
	{
		// 获取传入字符串的长度
		// 但是 , 字符串指针 指向的内存空间大小需要 +1 , 内容是 '\0'
		this->m_len = len;

		// 使用 new 关键字为 char* m_p; 指针分配内存
		// 对于基础数据类型 new 等同于 malloc
		this->m_p = new char[this->m_len + 1];

		// 将内存空间设置为 0 内容
		memset(this->m_p, 0, this->m_len);
	}
};

// 拷贝构造函数 , 使用 String 对象初始化 对象值
String::String(const String& s)
{
	// 拷贝字符串长度
	// 注意 : 字符串指针 指向的内存空间大小需要 +1 , 内容是 '\0'
	this->m_len = s.m_len;

	// 使用 new 关键字为 char* m_p; 指针分配内存
	// 对于基础数据类型 new 等同于 malloc
	this->m_p = new char[this->m_len + 1];

	// 拷贝字符串到 m_p 指向的内存中
	strcpy(this->m_p, s.m_p);

	cout << "调用拷贝构造函数" << endl;
}

// 析构函数
String::~String()
{
	if (this->m_p != NULL)
	{
		// 之前使用 new 分配的内存
		// 释放内存就需要使用 delete 
		// 使用 malloc 分配的内存需要使用 free 释放
		delete[] this->m_p;

		// 设置指针指为空 , 避免出现野指针
		this->m_p = NULL;

		// 设置字符串长度为 0
		this->m_len = 0;
	}
}

// 重载等号 = 操作符 , 右操作数是 String 对象的情况
String& String::operator=(const String& s)
{
	// 先处理本对象已分配的内存
	if (this->m_p != NULL)
	{
		// 之前使用 new 分配的内存
		// 释放内存就需要使用 delete 
		// 使用 malloc 分配的内存需要使用 free 释放
		delete[] this->m_p;

		// 设置指针指为空 , 避免出现野指针
		this->m_p = NULL;

		// 设置字符串长度为 0
		this->m_len = 0;
	}

	// 拷贝字符串长度
	// 注意 : 字符串指针 指向的内存空间大小需要 +1 , 内容是 '\0'
	this->m_len = s.m_len;

	// 使用 new 关键字为 char* m_p; 指针分配内存
	// 对于基础数据类型 new 等同于 malloc
	this->m_p = new char[this->m_len + 1];

	// 拷贝字符串到 m_p 指向的内存中
	strcpy(this->m_p, s.m_p);

	cout << "调用重载 等号 = 操作符函数 String& String::operator=(const String& s)" << endl;

	return *this;
}

// 重载等号 = 操作符 , 右操作数是 字符串常量值 的情况
String& String::operator=(const char* p)
{
	// 先处理本对象已分配的内存
	if (this->m_p != NULL)
	{
		// 之前使用 new 分配的内存
		// 释放内存就需要使用 delete 
		// 使用 malloc 分配的内存需要使用 free 释放
		delete[] this->m_p;

		// 设置指针指为空 , 避免出现野指针
		this->m_p = NULL;

		// 设置字符串长度为 0
		this->m_len = 0;
	}

	// 拷贝字符串长度
	// 注意 : 字符串指针 指向的内存空间大小需要 +1 , 内容是 '\0'
	this->m_len = strlen(p);

	// 使用 new 关键字为 char* m_p; 指针分配内存
	// 对于基础数据类型 new 等同于 malloc
	this->m_p = new char[this->m_len + 1];

	// 拷贝字符串到 m_p 指向的内存中
	strcpy(this->m_p, p);

	cout << "调用重载 等号 = 操作符函数 String& String::operator=(const char* p)" << endl;

	return *this;
}

// 重载 数组下标 [] 操作符
char& String::operator[](int i)
{
	cout << "调用重载 下标 [] 操作符函数 char& String::operator[](int i)" << endl;

	// 直接返回对应 i 索引字符
	return this->m_p[i];
}

// 重载 双等号 == 运算符
bool String::operator==(String& s)
{
	// 首先判断数组长度是否相等
	if (this->m_len != s.m_len)
	{
		return false;
	}

	for (size_t i = 0; i < this->m_len; i++)
	{
		// 只要有一个元素不相等, 整个数组就不相等
		if (this->m_p[i] != s.m_p[i])
		{
			return false;
		}
	}
	return true;
}

// 重载 不等号 != 运算符
bool String::operator!=(String& s)
{
	// 首先判断数组长度是否相等
	if (this->m_len != s.m_len)
	{
		return false;
	}

	for (size_t i = 0; i < this->m_len; i++)
	{
		// 只要有一个元素不相等, 整个数组就不相等
		if (this->m_p[i] != s.m_p[i])
		{
			return false;
		}
	}
	return true;
}

// 重载 大于 > 运算符
bool String::operator>(String& s)
{
	// 将 String 类比较转为 字符串比较 
	// 大于 和 小于 区别是 参数顺序不同的区别
	return strcmp(this->m_p, s.m_p);
}

// 重载 小于 < 运算符
bool String::operator<(String& s)
{
	// 将 String 类比较转为 字符串比较
	// 大于 和 小于 区别是 参数顺序不同的区别
	return strcmp(s.m_p, this->m_p);
}

// 获取私有成员 char* m_p
char* String::str()
{
	return this->m_p;
}

// 获取私有成员 int m_len
int String::len()
{
	return this->m_len;
}

// 全局函数 中实现 String 左移运算符重载
// 返回 ostream& 引用类型 , 是为了支持链式调用 cout << s1 << endl;
ostream& operator<<(ostream& out, String& s)
{
	cout << "调用重载 左移 << 操作符函数 ostream& operator<<(ostream& out, String& s)" << endl;

	// 在函数体中将 String 对象的 m_p 指针指向的数据输出到 out 输出流中
	out << s.m_p  << endl;

	// 该返回值还需要当左值使用
	return out;
}

// 全局函数 中实现 String 右移运算符重载
// 返回 istream& 引用类型 , 是为了支持链式调用 cin >> s1 >> endl;
istream& operator>>(istream& in, String& s)
{
	cin >> s.m_p;
	return in;
}

3、Test.cpp 测试类


#include "iostream"
using namespace std;

// 导入自定义的 String 类
#include "String.h"

int main() {

	// 调用无参构造函数
	String s1;

	// 调用有参构造函数
	String s2("Tom");

	// 调用拷贝构造函数
	String s3 = s2;

	// 调用重载的等号运算符函数, 右操作数是 String 对象
	s1 = s2;

	// 调用重载的等号运算符函数, 右操作数是 字符串常量值 , char* 指针类型
	s3 = "Jerry";

	// 调用重载的下标运算符函数
	char c = s3[3];

	// 调用 重载的 左移运算符 函数
	cout << s3 << endl;

	// 控制台暂停 , 按任意键继续向后执行
	system("pause");

	return 0;
}

到了这里,关于【C++】运算符重载案例 - 字符串类 ⑤ ( 重载 大于 > 运算符 | 重载 小于 < 运算符 | 重载 右移 >> 运算符 - 使用全局函数重载 | 代码示例 )的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【从零学习python 】06. Python中运用算数运算符进行计算和字符串拼接

    现代的计算机和依赖计算机的设备里都用到二进制(即0和1)来保存和表示数据,一个二进制表示一个比特(Bit)。 在二进制的基础上,计算机还支持八进制和十六进制这两种进制。 除了计算机里的进制以外,我们生活中经常用到的是十进制。 Python语言支持二进制、八进制、十六

    2024年02月13日
    浏览(38)
  • 【C&C++】为什么 scanf 函数在读取字符串时不需要用取地址运算符 &

    在C语言中,字符串实际上是字符数组,所以我们可以使用 scanf 函数来读取字符串。但是,需要注意的是, scanf 在读取字符串时会在遇到空格、制表符或换行符时停止。因此,它不能用于读取包含空格的字符串。 以下是使用 scanf 读取字符串的基本示例: 在这个例子中,我们

    2024年01月20日
    浏览(36)
  • 在 SQL Server 中,可以使用加号运算符(+)来拼接字符串。但是,如果需要拼接多个字符串或表中的字段,就需要使用内置的拼接函数了

    以下是 SQL Server 中的一些内置拼接函数: 1. CONCAT:将两个或多个字符串拼接在一起。语法为: 示例: 2. CONCAT_WS:与 CONCAT 类似,但可以指定一个分隔符。语法为: 示例: 3. CONCATN:将多个字符串拼接在一起,并在每个字符串之间添加指定的字符。语法为: 示例: 4. REPLAC

    2024年02月07日
    浏览(44)
  • 【C++】详解运算符重载,赋值运算符重载,++运算符重载

    目录 前言 运算符重载 概念 目的 写法 调用 注意事项 详解注意事项 运算符重载成全局性的弊端 类中隐含的this指针 赋值运算符重载 赋值运算符重载格式 注意点 明晰赋值运算符重载函数的调用 连续赋值 传引用与传值返回 默认赋值运算符重载 前置++和后置++重载 先梳理一下

    2024年04月25日
    浏览(56)
  • C++,运算符重载——关系运算符练习

    一、关系运算符重载 = = == !=  二、知识点整理  

    2024年02月11日
    浏览(32)
  • C++——运算符重载

    运算符重载,就是对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型。 运算符重载的目的是让语法更加简洁 运算符重载不能改变本来寓意,不能改变基础类型寓意 运算符重载的本质是另一种函数调用(是编译器去调用) 这个函数统一的名字叫opera

    2024年02月16日
    浏览(37)
  • 【C++】运算符重载

    目录 1. 基本概念 1.1 直接调用一个重载的运算符函数 1.2 某些运算符不应该被重载 1.3 使用与内置类型一致的含义 1.4 赋值和复合赋值运算符 1.5 选择作为成员或者非成员 2. 输入和输出运算符 2.1 输出运算符重载 2.2 输入运算符重载 3. 算术和关系运算符 3.1 算数运算符重载 3.2

    2024年02月11日
    浏览(35)
  • C++:重载运算符

    1.重载不能改变运算符运算的对象个数 2.重载不能改变运算符的优先级别 3.重载不能改变运算符的结合性 4.重载运算符必须和用户定义的自定义类型的对象一起使用,其参数至少应该有一个是类对象,或类对象的引用 5.重载运算符的功能要类似于该运算符作用于标准类型数据

    2024年02月10日
    浏览(35)
  • 复习 --- C++运算符重载

    .5 运算符重载 运算符重载概念:对已有的运算符重新进行定义,赋予其另外一种功能,以适应不同的数据类型 4.5.1 加号运算符重载 作用:实现两个自定义数据类型相加的运算 4.5.2 左移运算符重载 4.5.3递增运算符重载 作用:通过重载递增运算符,实现自己的整型数据 4.5.4 赋

    2024年02月07日
    浏览(34)
  • C++——类和对象3|日期类型|Cout运算符重载|Cin运算符重载|const成员|

    目录 日期类型  Date.h  Date.cpp  Test.cpp  实现Cout运算符重载  实现Cin运算符重载  根据日期算星期  修改后完整代码   Date.h  Date.cpp  const成员  取地址及const取地址操作符重载 习题  计算日期到天数转换     一个类到底可以重载哪些运算符,要看哪些运算符对这个类型有

    2023年04月13日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包