【C++】泛型编程 ⑨ ( 类模板的运算符重载 - 函数声明 和 函数实现 写在同一个类中 | 类模板 的 外部友元函数问题 )

文章目录

  • 一、类模板 - 函数声明与函数实现分离
    • 1、函数声明与函数实现分离
    • 2、代码示例 - 函数声明与函数实现分离
    • 3、函数声明与函数实现分离 + 友元函数引入
  • 二、普通类的运算符重载 - 函数声明 和 函数实现 写在同一个类中
  • 三、类模板的运算符重载 - 函数声明 和 函数实现 写在同一个类中
    • 1、类模板 的 外部友元函数问题
    • 2、代码示例 - 类模板 函数声明 和 函数实现 写在同一个类中 ( 包括友元函数 )






一、类模板 - 函数声明与函数实现分离




1、函数声明与函数实现分离


项目开发中 , 需要 将 函数声明 与 函数实现 分开进行编码 ;


将 函数声明 与 函数实现 分开进行编码 , 有 三种 方式 :

  • 类模板 的 函数声明 与 函数实现 都写在同一个类中 ;
  • 类模板 的 函数实现 在 类外部进行 , 写在相同的 .h 和 .cpp 源码文件中 ;
  • 类模板 的 函数实现 在 类外部进行 , 写在不同的 .h 和 .cpp 源码文件中 ;

2、代码示例 - 函数声明与函数实现分离


对于下面的 Father 类中的 printValue 函数 ,

// 声明 类模板 父类
template <typename T>
class Father {
public:
    T value;
    Father(T val) : value(val) {}
    void printValue() {
        std::cout << value << std::endl;
    }
};

如果要在外部 实现 printValue 的话 , 写法如下 :

// 声明 类模板 父类
template <typename T>
class Father {
public:
    T value;
    Father(T val) : value(val) {}
    void printValue();
};

// 在 类模板 外部实现函数
template <typename T>
void Father<T>::printValue()
{
    std::cout << value << std::endl;
}

每个函数前面都要加上 template <typename T> 类型参数列表声明 ,

使用域作用符 Father<T>:: 访问函数 ;


3、函数声明与函数实现分离 + 友元函数引入


如果要在 类模板 中进行运算符重载 , 就需要用到友元函数 ;

如果将 类模板 的 函数实现 , 定义在函数外部 , 结合 友元函数 使用 , 就变得很复杂 , 下面针对该问题进行讨论 ;





二、普通类的运算符重载 - 函数声明 和 函数实现 写在同一个类中



下面的类是一个 普通类 , 其中定义了 成员变量 和 成员方法 ;

并为其重载了 左移运算符 和 加法运算符 ;

其中 加法运算符 重载 是在 类内部实现的 ,

左移运算符 重载 是在类外部 通过友元函数实现的 , 因为左移运算符的 左操作数是 ostream& 类型的 , 如果定义在了 类内部 , 左操作数就默认为当前类 ;


代码示例 :

#include "iostream"
using namespace std; 

class Student
{
	// 左移运算符重载
	friend ostream& operator<<(ostream& out, Student& s)

public:
	Student(int x = 0, int y = 0)
	{
		this->a = x;
		this->b = y;
	}

	// 重载 + 运算符
	Student operator+(Student& s)
	{
		Student student(this->a + s.a, this->b + s.b);
		return student;
	}

	// 打印类成员变量
	void printStudent()
	{
		cout << "a = " << a << " , b = " << b << endl;
	}

public:
	int a, b;
};

// 重载左移运算符
ostream& operator<<(ostream& out, Student& s)
{
	out << "a:" << s.a << " b: " << s.b << endl;
	return out;
}

int main() {
	Student s(666, 888);
	s.printStudent();
	
	// 控制台暂停 , 按任意键继续向后执行
	system("pause");

	return 0;
}

执行结果 :

10
666
88
66
Press any key to continue . . .

在这里插入图片描述





三、类模板的运算符重载 - 函数声明 和 函数实现 写在同一个类中




1、类模板 的 外部友元函数问题


将上述 " 普通类的运算符重载 - 函数声明 和 函数实现 写在同一个类中 " 示例改造成 类模板 示例 ;

问题就出现在 定义在外部的 友元函数 中 ,

友元函数 , 不能 读取 和 访问 到 泛型类型 T , 也就是 类模板 中 的 template <typename T> 泛型类型 T ;

在外部重新定义 template <typename T> 就是重新定义了一个新的泛型 , 与 类模板 中的 T 不是同一个泛型类型 ;

在这里插入图片描述

解决上述问题 , 就需要将 友元函数 定义在 类模板 的内部 ;

template <typename T>
class Student
{
	// 左移运算符重载
	friend ostream& operator<<(ostream& out, Student& s2)
	{
		out << "a:" << s.a << " b: " << s.b << endl;
		return out;
	}
}

2、代码示例 - 类模板 函数声明 和 函数实现 写在同一个类中 ( 包括友元函数 )


代码示例 :

#include "iostream"
using namespace std; 

template <typename T>
class Student
{
	// 左移运算符重载
	friend ostream& operator<<(ostream& out, Student& s)
	{
		out << "a:" << s.a << " b: " << s.b << endl;
		return out;
	}

public:
	Student(T x, T y)
	{
		this->a = x;
		this->b = y;
	}

	// 重载 + 运算符
	Student operator+(Student& s)
	{
		Student student(this->a + s.a, this->b + s.b);
		return student;
	}

	// 打印类成员变量
	void printStudent()
	{
		cout << "a = " << a << " , b = " << b << endl;
	}

public:
	T a, b;
};

// 重载左移运算符
//ostream& operator<<(ostream& out, Student& s)
//{
//	out << "a:" << s.a << " b: " << s.b << endl;
//	return out;
//}

int main() {
	// 模板类不能直接定义变量
	// 需要将 模板类 具体化之后才能定义变量
	Student<int> s(666, 888);
	s.printStudent();

	Student<int> s2(222, 111);
	s2.printStudent();

	// 验证 加法运算符 + 重载
	Student<int> s3 = s + s2;
	s3.printStudent();

	// 验证 左移运算符 << 重载
	cout << s3 << endl;
	
	// 控制台暂停 , 按任意键继续向后执行
	system("pause");

	return 0;
}

执行结果 :

a = 666 , b = 888
a = 222 , b = 111
a = 888 , b = 999
a:888 b: 999

Press any key to continue . . .

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/173652.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java实现windows系统截图

Java提供了一种方便的方式来截取Windows系统的截图。这个过程通常需要使用Java的Robot类来模拟用户的鼠标和键盘输入操作。下面将介绍如何使用Java实现Windows系统截图。 步骤1&#xff1a;导入Robot和AWT包 Java提供了一个Robot类&#xff0c;它可以模拟用户的键盘和鼠标操作…

医疗器械维修售后技术培训与支持的重要性

医疗器械维修售后技术培训与支持的重要性 随着我国医疗器械产业的的高速发展、医疗器械企业的崛起,大量创新医疗器械产品进入医疗机构。但医疗设备在使用和维护过程中,暴露出许多问题和不足,如部分设备故障率较高、临床工程培训不足、售后服务模式整体比较落后等,这影响了医疗…

当前系统并无桌面环境,或无显示器,无法显示远程桌面,您需要自行安装X11桌面环境,或者使用终端文件功能

ToDesk远程遇到的问题如上图&#xff0c;换向日葵直接黑屏&#xff1b; 问题原因 截止发文时间&#xff0c;Todesk只支持X11协议&#xff0c;没有适配最新的Wayland协议&#xff0c;所以我们需要把窗口系统调整为X11才可以。 解决方法 修改配置文件&#xff0c;关闭wayland su…

c# 文件读取和写入

文件写入 using System.Collections.Generic; namespace demo1;/// <summary> /// System.IO下的所有的Stream类是所有数据流的基类 /// 流是用于传输数据的对象&#xff0c;流就是用来传输数据的 /// 数据传输的两种方式&#xff1a;1、数据从外部源传输到程序中&#…

技术互联 创新交流 | 广汽研究院举办技术交流会圆满落幕

技术互联 创新交流 2023年11月1日&#xff0c;同星智能走进广汽研究院技术交流会圆满举行并落下帷幕。本次技术交流会得到广汽研究院相关部门的大力支持&#xff0c;并邀请到多名人员参与&#xff0c;涉及其技术、研发等部门。 本次活动的举办意义重大&#xff0c;目前广汽研究…

如何把A3 pdf 文章打印成A4

1. 用Adobe Acrobat 打开pdf 2 打印 选择海报 进行调整即可如下图,见下面红色的部分。

互联网医院源码搭建部署功能

互联网将医院与患者、医院内部&#xff08;医生、护士、领导层&#xff09;、医院与生态链上的各类组织机构连接起来。以患者为中心&#xff0c;优化医院业务流程&#xff0c;提升医疗服务质量与医院资源能效&#xff0c;让患者通过移动互联网随时随地的享受医院的服务&#xf…

练习八-利用有限状态机进行时序逻辑的设计

利用有限状态机进行时序逻辑的设计 1&#xff0c;任务目的&#xff1a;2&#xff0c;RTL代码&#xff0c;及原理框图3&#xff0c;测试代码&#xff0c;输出波形 1&#xff0c;任务目的&#xff1a; &#xff08;1&#xff09;掌握利用有限状态机实现一般时序逻辑分析的方法&am…

vue3中使用v-html解析后table表格的线不展示

在vue3中使用v-html展示富文本内容时&#xff0c;表格的框线不展示 在使用网上关于 ::v-deep /deep/ 各种用法之后&#xff0c;还是不生效 最后直接在scoped模式下的style&#xff0c;重新建一个&#xff0c;scoped模式会影响内部重新设置表格的样式

报名仅剩一周!课程直播和1V1指导助力文心一言插件开发赛事冲榜

百度联合CCF大数据与计算智能大赛发布文心一言插件设计与开发赛题&#xff0c;初赛倒计时最后一周&#xff01; 为了帮助各位选手完善插件功能设计&#xff0c;冲击更好名次&#xff0c;在11月23日24点前提交初赛作品的前20个队伍&#xff0c;可以获得1v1技术方案指导和百度精…

利用SVD对图像进行压缩

利用SVD对图像进行压缩 使用SVD能够对数据进行降维&#xff0c;对图像进行SVD&#xff0c;降维之后然后重构数据&#xff0c;还原后的图像就是压缩后的图像。 SVD SVD进行图像压缩所依据的数学原理就是矩阵的近似表示&#xff1a; A m n ≈ U m k ∑ k k V k n T A_{m\…

Java入门篇 之 内部类

本篇碎碎念&#xff1a;本篇没有碎碎念&#xff0c;想分享一段话&#xff1a; 你不笨&#xff0c;你只是需要时间&#xff0c;耐心就是智慧&#xff0c;不见得快就好&#xff0c;如果方向都不对&#xff0c;如果心术不正&#xff0c;如果德不配位&#xff0c;快就是对自己天分的…

Go——二、变量和数据类型

Go 一、Go语言中的变量和常量1、Go语言中变量的声明2、如何定义变量方式1&#xff1a;方式2&#xff1a;带类型方式3&#xff1a;类型推导方式定义变量方式4&#xff1a;声明多个变量总结 3、如何定义常量4、Const常量结合iota的使用 二、Golang的数据类型1、概述2、整型2.1 类…

Windows配置全局代理

一. Windows下为PowerShell/CMD/Git设置代理 —————————————————————————————————————————————————————— 二. [WinError 10061] 由于目标计算机积极拒绝&#xff0c;无法连接。 keyerror:192。 HTTP Error 403: Forbidd…

python实战—数据分析与图表1(QQ群聊天数据分析) lv2

目录 一、核心代码解释 二、代码 三、运行截图 一、核心代码解释 1、readlines() 方法 描述 readlines() 方法用于读取所有行(直到结束符 EOF)并返回列表&#xff0c;该列表可以由 Python 的 for... in ... 结构进行处理。 如果碰到结束符 EOF 则返回空字符串。 语法 r…

Monitor 原理

每个 Java 对象都可以关联一个 Monitor 对象&#xff0c;如果使用 synchronized 给对象上锁&#xff08;重量级&#xff09;之后&#xff0c;该对象头的 Mark Word 中就被设置指向 Monitor 对象的指针。 Monitor组成内容 EntryList&#xff08;入口列表&#xff09; 当一个线…

STM32F4串口USART发送为00的解决方案

检查接线是否正确检查TX是否为复用推挽输出 3.检查是否将TX和RX引脚重映射为USART功能 在STM32中&#xff0c;每个GPIO引脚可以配置为不同的复用功能&#xff0c;例如UART、SPI、I2C等。具体来说&#xff0c;GPIO_PinAFConfig函数用于配置GPIO引脚的复用功能。它的参数包括GPIO…

ANSYS中如何手动为装配体添加接触约束教程

接触的类型&#xff1a; 在接触类型&#xff08;Type&#xff09;选项中&#xff0c;软件共提供了绑定接触&#xff08;Bonded&#xff09;、不分离接触&#xff08;No Separation&#xff09;、无摩擦接触&#xff08;Frictionless&#xff09;、粗糙接触&#xff08;Rough&a…

新一代最强开源UI自动化测试神器Playwright(Java版)(对话框处理)

&#x1f3ad;Playwright让网页对话框&#x1f310;&#x1f4ac;处理变得更加快捷&#xff01;网页对话框是在网页上出现的常见弹窗&#xff0c;包括Alert、Confirm和Prompt等。这些对话框通常需要用户输入信息或进行某些选择&#xff0c;但是在自动化测试中处理它们可能会很棘…

全球首款容器计算产品重磅发布,激活上云用云新范式

云布道师 10 月 31 日&#xff0c;杭州云栖大会上&#xff0c;阿里云云原生应用平台负责人丁宇宣布&#xff0c;阿里云容器计算服务 ACS 正式发布&#xff01;ACS 将大幅降低企业和开发者用云门槛&#xff0c;真正将 Serverless 理念大规模落地。 容器计算服务 ACS&#xff0c…