【C++】泛型编程 ⑩ ( 类模板的运算符重载 - 函数实现 写在类外部的同一个 cpp 代码中 | 类模板 的 外部友元函数二次编译问题 )

文章目录

  • 一、类模板 - 函数声明与函数实现分离
    • 1、类模板 外部 实现 构造函数
    • 2、类模板 外部 实现 普通函数
    • 3、类模板 外部 实现 友元函数
        • ( 1 ) 错误示例及分析 - 类模板 的 外部友元函数 二次编译 问题
        • ( 2 ) 正确写法
  • 二、代码示例 - 函数声明与函数实现分离
    • 1、代码示例
    • 2、执行结果


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

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

上一篇博客 【C++】泛型编程 ⑨ ( 类模板的运算符重载 - 函数声明 和 函数实现 写在同一个类中 | 类模板 的 外部友元函数问题 ) 实现了第一种情况 , 类模板 的 函数声明 与 函数实现 都写在同一个类中 , 也就是没有分开进行编码 ;

本篇博客 , 开始分析 第二种情况 , 类模板 的 函数实现 在 类外部进行 , 写在相同的 .h 和 .cpp 源码文件中 ;





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




1、类模板 外部 实现 构造函数


原来的构造函数是 :

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

如果将 构造函数 实现 , 写在类外部的 .cpp 源码中 ,

  • 首先 , 需要 声明 模板类型 , template <typename T> ;
  • 然后 , 通过 域操作符 访问 构造函数 , 并实现该函数 , 使用域操作符 时 , 前面的类 需要指定 具体的泛型类型 , 这里使用 声明的 T 模板类型 作为 具体的 泛型类型 ;
template <typename T>
Student<T>::Student(T x, T y)
{this->a = x;this->b = y;
}

在 类模板 内部 , 只需要声明该 构造函数 :

template <typename T>
class Student
{
public:Student(T x, T y);
}

2、类模板 外部 实现 普通函数


将 类内部的 普通函数 实现 加法运算符重载 的函数 , 提取到 类模板 外部进行定义 ;

该函数的 返回值 和 参数 都涉及到 类模板 类型 ;

template <typename T>
class Student
{
public:// 重载 + 运算符Student operator+(Student& s){Student student(this->a + s.a, this->b + s.b);return student;}
}

在类外部 实现 该 加号运算符重载 需要注意以下几点 :

  • 首先 , 需要 声明 模板类型 , template <typename T> ;
  • 然后 , 通过 域操作符 访问 构造函数 , Student<T>:: 后面跟上要访问的成员 ;
  • 最后 , 返回值和参数类型 , 如果是 类模板类型 Student , 需要在后面使用尖括号 指明具体的类型 , 这里具体的类型就是泛型 T ;

函数内部 Student 类型 , 可以加 <T> 也可不加 <T> , 不加 <T> 也可以使用 , 加了也不会报错 ;

// 重载 + 运算符
// 使用  Student<T>:: 域操作符访问函数
template <typename T>
Student<T> Student<T>::operator+(Student<T>& s)
{// 函数内部的类的 <T> 模板类型 , 可加 <T> 可不加 <T> // 不加 <T> 也可以使用 , 加了也不会报错Student student(this->a + s.a, this->b + s.b);return student;
}

类模板内部 , 需要声明该 重载函数 ;

template <typename T>
class Student
{
public:// 重载 + 运算符Student operator+(Student& s);
}

3、类模板 外部 实现 友元函数


友元函数 不是 类中的函数 , 是 类外部的函数 , 友元函数 中又用到了 泛型 T , 说明这是一个 模板函数 ;

友元函数 是 全局函数 , 不属于 类模板 , 不要使用 域操作符 访问友元函数 ;

友元函数 中的 泛型类型 , 要当做 函数模板 对待 ;

模板函数就涉及到 二次编译 问题 , 下面先分析一下 模板函数 二次编译 导致的 类模板的友元函数 问题 ;

友元函数 不要乱用 , 只有在 重载 左移 右移 操作符时 , 才使用 友元函数 ;



( 1 ) 错误示例及分析 - 类模板 的 外部友元函数 二次编译 问题

在 类模板 内部声明 友元函数 ,

template <typename T>
class Student
{// 左移运算符重载friend ostream& operator<<(ostream& out, Student& s);
}

在 类外部 实现 友元函数 ,

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

运行时会报如下错误 :

已启动生成…
1>------ 已启动生成: 项目: HelloWorld, 配置: Debug Win32 ------
1>Test.obj : error LNK2019: 无法解析的外部符号 "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class Student<int> &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@AAV?$Student@H@@@Z),函数 _main 中引用了该符号
1>D:\002_Project\006_Visual_Studio\HelloWorld\HelloWorld\Debug\HelloWorld.exe : fatal error LNK1120: 1 个无法解析的外部命令
1>已完成生成项目“HelloWorld.vcxproj”的操作 - 失败。
========== 生成: 成功 0 个,失败 1 个,最新 0 个,跳过 0==========

造成上述错误的原因 就是 函数模板 的实现机制 中的 二次编译 有关 ,

  • 第一次编译 函数模板 时 , 只进行 简单的 语法分析 , 词法分析 , 生成一个函数头 ;
  • 第二次编译 函数模板 时 , 又生成一个 函数头 ;

这两次编译生成的 函数头 不一致 , 导致 无法找到 相应的 函数实现 ;


( 2 ) 正确写法

友元函数 不要乱用 , 只有在 重载 左移 右移 操作符时 , 才使用 友元函数 ;


这是 函数模板 二次编译 问题 ,

一般情况下 , 函数模板 只有在 调用时 , 才需要将 泛型类型 指明 , 在 函数名称后面 , 使用 <> 注明泛型类型 ,

但是在 类模板 声明 友元函数 时 , 就需要指定 泛型类型 ;

这样才能将 类模板中的 泛型 T , 与 友元函数在 外部实现时 声明的 template <typename T> 关联起来 ;


在 类模板 内部声明 友元函数时 , 在函数名 operator<< 后面 加上 <T> ;

template <typename T>
class Student
{// 左移运算符重载friend ostream& operator<< <T> (ostream& out, Student& s);
}

在 类外部 实现 友元函数 保持不变 ;

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




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




1、代码示例


#include "iostream"
using namespace std; template <typename T>
class Student
{// 左移运算符重载friend ostream& operator<< <T> (ostream& out, Student& s);public:// 构造函数Student(T x, T y);// 重载 + 运算符Student operator+(Student& s);public:T a, b;
};// 类模板构造函数
// 使用  Student<T>:: 域操作符访问函数
template <typename T>
Student<T>::Student(T x, T y)
{this->a = x;this->b = y;
}// 重载 + 运算符
// 使用  Student<T>:: 域操作符访问函数
template <typename T>
Student<T> Student<T>::operator+(Student<T>& s)
{// 函数内部的类的 <T> 模板类型 , 可加 Student<T> 可不加 Student// 不加 <T> 也可以使用 , 加了也不会报错Student student(this->a + s.a, this->b + s.b);return student;
}// Student 类的友元函数
// 左移运算符重载 函数
template <typename T>
ostream& operator<<(ostream& out, Student<T>& s)
{out << "a:" << s.a << " b: " << s.b << endl;return out;
}int main() {// 模板类不能直接定义变量// 需要将 模板类 具体化之后才能定义变量Student<int> s(666, 888);cout << s << endl;Student<int> s2(222, 111);cout << s2 << endl;// 验证 加法运算符 + 重载Student<int> s3 = s + s2;// 验证 左移运算符 << 重载cout << s3 << endl;// 控制台暂停 , 按任意键继续向后执行system("pause");return 0;
}

2、执行结果


执行结果 :

a:666 b: 888a:222 b: 111a:888 b: 999Press any key to continue . . .

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

90天,广告商单43张,小红书AI庭院风视频制作详解教程

今天给大家分享一个目前在小红书很火的AI绘画商单号案例。 首先给大家看看案例视频形态 这类视频内容非常简单&#xff0c;主要展示农家庭院的别致景色。通过AI绘画工具生成图片&#xff0c;再利用剪辑工具将画面增加动态元素&#xff0c;让整个视频逼真鲜活&#xff0c;加上…

Head、Neck、Backbone介绍

在深度学习中&#xff0c;通常将模型分为三个部分&#xff1a;backbone、neck 和 head。 Backbone&#xff1a;backbone 是模型的主要组成部分&#xff0c;通常是一个卷积神经网络&#xff08;CNN&#xff09;或残差神经网络&#xff08;ResNet&#xff09;等。backbone 负责…

使用Pytorch实现linear_regression

使用Pytorch实现线性回归 # import necessary packages import torch import torch.nn as nn import numpy as np import matplotlib.pyplot as plt# Set necessary Hyper-parameters. input_size 1 output_size 1 num_epochs 60 learning_rate 0.001# Define a Toy datas…

基于单片机仓库温湿度监测报警系统仿真设计

**单片机设计介绍&#xff0c;基于单片机仓库温湿度监测报警系统仿真设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机的仓库温湿度监测报警系统可以被设计成能够实时监测仓库内的温度和湿度&#xff0c;并根据预设…

【C++】继承(上) 继承 | 子类的默认成员函数

一、继承 概念 继承(inheritance)是一种面向对象编程的概念&#xff0c;它允许一个类&#xff08;称为子类或派生类&#xff09;继承另一个类&#xff08;称为父类或基类&#xff09;的特征和行为。子类可以获得父类的成员函数和变量&#xff0c;而不需要重新编写它们。子类还…

这是一棵适合搜索二叉树

&#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ &#x1f43b;强烈推荐优质专栏: &#x1f354;&#x1f35f;&#x1f32f;C的世界(持续更新中) &#x1f43b;推荐专栏1: &#x1f354;&#x1f35f;&#x1f32f;C语言初阶 &#x1f43b;推荐专栏2: &#x1f354;…

宏集新闻 | 虹科传感器事业部正式更名为宏集科技

致一直支持“虹科传感器”的朋友们&#xff1a; 为进一步整合资源&#xff0c;给您带来更全面、更优质的服务&#xff0c;我们非常荣幸地宣布&#xff0c;虹科传感器事业部已正式更名为宏集科技。这一重要的改变代表了虹科持续发展进程中的新里程碑&#xff0c;也体现了我们在传…

安装gitlab

安装gitlab 环境 关闭防火墙以及selinux&#xff0c;起码4核8G 内存至少 3G 不然启动不了 下载环境 gitlab官网&#xff1a;GitLab下载安装_GitLab最新中文基础版下载安装-极狐GitLab rpm包下载地址&#xff1a; [Yum - Nexus Repository Manager (gitlab.cn)](https://pack…

Android studio run 手机或者模拟器安装失败,但是生成了debug.apk

错误信息如下&#xff1a;Error Installation did not succeed. The application could not be installed&#xff1a;List of apks 出现中文乱码&#xff1b; 我首先尝试了打包&#xff0c;能正常安装&#xff0c;再次尝试了debug的安装包&#xff0c;也正常安装&#xff1…

报错!Jupyter notebook 500 : Internal Server Error

Jupyter notebook 报错 500 : Internal Server Error 问题背景 tensorflow-gpu环境&#xff0c;为跑特定代码专门开了一个环境&#xff0c;使用conda安装了Jupyter notebook&#xff0c;能够在浏览器打开Jupyter notebook&#xff0c;但是notebook打开ipynb会报错。 问题分析…

抖音seo矩阵系统源代码部署及产品功能设计分析

一、引言 随着抖音等短视频平台的崛起&#xff0c;越来越多的企业和个人开始关注如何在这些平台上提升曝光量和用户流量。抖音SEO&#xff08;搜索引擎优化&#xff09;是一种有效的方法&#xff0c;通过优化短视频内容和关键词&#xff0c;让更多的人找到并点击你的视频。本文…

【css】Google第三方登录按钮样式修改

文章目录 场景前置准备修改样式官方属性修改样式CSS修改样式按钮的高度height和border-radiusLogo和文字布局 场景 需要用到谷歌的第三方登录&#xff0c;登录按钮有自己的样式。根据官方文档&#xff1a;概览 | Authentication | Google for Developers&#xff0c;提供两种第…

【Web】Ctfshow Nodejs刷题记录

目录 ①web334 ②web335 ③web336 ④web337 ⑤web338 ⑥web339 ⑦web340 ⑧web341 ⑨web342-343 ⑩web344 ①web334 进来是一个登录界面 下载附件&#xff0c;简单代码审计 表单传ctfshow 123456即可 ②web335 进来提示 get上传eval参数执行nodejs代码 payload: …

基于安卓android微信小程序的个人管理小程序

运行环境 开发语言&#xff1a;Java 框架&#xff1a;ssm JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09; 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&a…

B站短视频如何去水印?一键解析下载B站视频!

在浏览B站视频时&#xff0c;我们有时会遇到带有水印的场景。这些水印可能会干扰我们对视频内容的观看体验&#xff0c;特别是在全屏观看时。此外&#xff0c;当我们想要保存或分享这些视频时&#xff0c;水印也会成为一种障碍。因此&#xff0c;去除水印的需求就变得非常迫切。…

035、目标检测-物体和数据集

之——物体检测和数据集 目录 之——物体检测和数据集 杂谈 正文 1.目标检测 2.目标检测数据集 3.目标检测和边界框 4.目标检测数据集示例 杂谈 目标检测是计算机视觉中应用最为广泛的&#xff0c;之前所研究的图片分类等都需要基于目标检测完成。 在图像分类任务中&am…

wsl安装ubuntu的问题点、处理及连接

WSL安装Ubuntu的参考链接 (41条消息) wsl报错&#xff1a;WslRegisterDistribution failed with error: 0x800701bc_yzpyzp的博客-CSDN博客_0x800701bc wsl (41条消息) 使用Ubuntu安装软件出现Unable to locate package错误解决办法_大灰狼学编程的博客-CSDN博客 手把手教你…

栈的生长方向不总是向下

据我了解&#xff0c;栈的生长方向向下&#xff0c;内存地址由高到低 测试 windows下&#xff1a; 符合上述情况 测试Linux下&#xff1a; 由此可见&#xff0c;栈在不同操作系统环境下&#xff0c;生长方向不总是向下

时序预测 | MATLAB实现基于LSTM-AdaBoost长短期记忆网络结合AdaBoost时间序列预测

时序预测 | MATLAB实现基于LSTM-AdaBoost长短期记忆网络结合AdaBoost时间序列预测 目录 时序预测 | MATLAB实现基于LSTM-AdaBoost长短期记忆网络结合AdaBoost时间序列预测预测效果基本介绍模型描述程序设计参考资料 预测效果 x 基本介绍 1.Matlab实现LSTM-Adaboost时间序列预测…

Android HAL学习 及 与BSP的区别

Android HAL学习 及 与BSP的区别 参考链接&#xff1a; 1、https://www.cnblogs.com/looner/articles/11579335.html 2、https://blog.csdn.net/leesan0802/article/details/124087630 3、https://zhuanlan.zhihu.com/p/336531442 在HAL的学习之前&#xff0c;我们来先了解…