C++模板 类模板成员函数类外实现 类模板分文件编写的问题与解决方法 类模板配合友元函数的类内和类外实现

2023-10-26

1 类模板成员函数类外实现

学习目标: 能够掌握类模板中的成员函数类外实现
场景描述: 创建一个类,类中只写函数的声明,类外写实现

template<class T1, class T2>
class Person
{
public:
	Person(T1 name, T2 age);//类内声明
	void showPerson();//类内声明
	T1 mname;
	T2 mage;
};
//构造函数类外实现
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age)
{
	this->mname = name;
	this->mage = age;
}
//成员函数类外实现
template<class T1, class T2>
void Person<T1, T2>::showPerson()
{
	cout << "姓名:" << this->mname << "\t年龄:" << this->mage << endl;
}

在这里插入图片描述

注意点: 构造函数/成员函数类外实现

1.构造函数前要加作用域——Person::
2.在构造函数前,声明类模板的参数,让编译器知道T1、T2的存在——template<class T1, class T2>
3.加模板的参数列表,表明Person是一个类模板——<T1, T2>,如果没有这个,Person只是一个普通类的类外实现

总结: 类模板中成员函数类外实现时,需要加上模板参数列表

2 类模板分文件编写

学习目标: 掌握类模板成员函数分文件编写产生的问题以及解决方式

问题: 类模板中成员函数创建时机是在调用阶段,导致分文件编写时链接不到

解决方法:

  • 解决方法1:直接包含.cpp源文件
  • 解决方法2:将声明和实现写到同一个文件中,并更改后缀名为.hpp,hpp是约定的名称,并不是强制

场景描述: 创建头文件写类声明,创建源文件写类实现
头文件Person.h

#pragma once
#include <iostream>
using namespace std;

template<class T1, class T2>
class Person
{
public:
	Person(T1 name, T2 age);
	void showPerson();
	T1 mname;
	T2 mage;
};

源文件Person.cpp

#pragma once
#include <iostream>
using namespace std;

template<class T1, class T2>
class Person
{
public:
	Person(T1 name, T2 age);
	void showPerson();
	T1 mname;
	T2 mage;
};

测试文件:

#include <iostream>
using namespace std;

//类模板分文件编写
#include "Person.h"
void test()
{
	Person<string, int> p1("Annas", 25);
	p1.showPerson();
}

int main()
{
	test();
	cout << endl;

	system("pause");
	return 0;
}

解释:
此时无法正常编译,因为类模板中Person构造函数和showPerson成员函数在一开始分文见编写时是不会创建的,成员函数的创建时机是在调用阶段,之前的学习笔记有讲到,导致分文件编写时链接不到。

具体来说,在测试文件中,如果包含“Person.h”这个头文件,即使编译器找到Person类,不会生成类中的Person和showPerson这两个成员函数,不会链接到Person.cpp源文件,所以不会生成这两个函数。也就是说,在一开始头文件中,类的成员函数并没有创建,导致无法链接到Person.cpp,从而不能调用类的两个成员函数。

解决办法1:包含源文件,不常用
在测试文件中,把包含的头文件“Person.h”的后缀“.h”改成“.cpp”,就可以正常调用了。相当于让编译器直接找到类的两个成员函数的具体实现。

#include "Person.cpp"

但是这种方法在实际中并不常用,通常不会让程序员直接看源码,而是看头文件。

解决办法2:将.h和.cpp的内容写到一起,并将头文件.h的后缀名改为.hpp,常用

//Person.hpp文件
#pragma once
#include <iostream>
using namespace std;

template<class T1, class T2>
class Person
{
public:
	Person(T1 name, T2 age);
	void showPerson();
	T1 mname;
	T2 mage;
};

template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age)
{
	this->mname = name;
	this->mage = age;
}

template<class T1, class T2>
void Person<T1, T2>::showPerson()
{
	cout << "姓名:" << this->mname << "\t年龄:" << this->mage << endl;
}

//测试文件
#include "Person.hpp"

在这里插入图片描述
注意点:

  1. .hpp文件中的类一般都是类模板
  2. .hpp是约定俗成的
  3. 直接包含**.hpp**文件

总结:
知道分文见编写出现的问题以及两种解决方法
主流的解决方式是第二种,将类模板成员函数写到一起,并将后缀名改为.hpp

3 类模板友元

学习目标: 掌握类模板配合友元函数的类内和类外实现

全局函数的实现:

  • 全局函数类内实现:直接在类内声明友元即可
  • 全局函数类外实现:需要提前让编译器知道全局函数的存在

场景描述: 创建一个类,让全局函数类内实现和类外实现,访问类的私有属性

类内实现-代码展示:

template<class T1, class T2>
class Person
{
	//全局函数类内实现 做友元 让printPerson可以访问Person的私有属性
	friend void printPerson1(Person<T1, T2> p)//Person<T1, T2>是类模板
	{
		cout << "姓名:" << p.mname << "\t年龄:" << p.mage << endl;
	}
public:
	Person(T1 name, T2 age)
	{
		this->mname = name;
		this->mage = age;
	}
private:
	T1 mname;
	T2 mage;
};

在这里插入图片描述
注意点: 全局函数在类内实现时:只需要在类内声明友元即可,加friend关键字

类外实现-代码展示:

//让编译器提前知道printPerson2中的Person是类模板
template<class T1, class T2> class Person;//类模板声明

//如果声明了函数模板,全局函数的实现可以写在后面,否则需要将实现体写在类内的前面,让编译器提前知道
template<class T1, class T2>
void printPerson2(Person<T1, T2> p)
{
	cout << "姓名:" << p.mname << "\t年龄:" << p.mage << endl;
}

template<class T1, class T2>
class Person
{
	//全局函数类外实现 类内声明
	//如果全局函数是函数模板且类外实现,需要让编译器提前知道这个函数的存在
	friend void printPerson2<>(Person<T1, T2> p);//加空模板参数列表<>
public:
	Person(T1 name, T2 age)
	{
		this->mname = name;
		this->mage = age;
	}
private:
	T1 mname;
	T2 mage;
};

在这里插入图片描述

注意点:
如果只是在类外写了全局函数的实现体,没有其他声明。此时编译器不知道printPerson3是什么类型的函数,是普通函数还是类模板的成员函数?

其实,printPerson3是普通函数,在类内仅做了声明。但在类外,由于printPerson3的前面加了函数模板声明template<class T1, class T2>,所以printPerson3在类外是一个函数模板的实现。由于printPerson3在类内、类外不一致,导致无法正常编译。因此,有如下步骤

首先,为了在类内表明printPerson3是一个函数模板的声明,需要在类内做友元时加空模板参数列表<>,即friend void printPerson3<>(Person<T1, T2> p);

其次,如果全局函数是函数模板,且类外实现,需要让编译器提前知道这个函数的存在。也就是将printPerson3的实现体放在类模板的前面。如果声明了函数模板,全局函数的实现也可以写在后面。

最后,还要声明printPerson3中的Person是一个类模板。

**总结:**建议全局函数做类内实现,用法简单,而且编译器可以直接识别

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++模板 类模板成员函数类外实现 类模板分文件编写的问题与解决方法 类模板配合友元函数的类内和类外实现 的相关文章

  • 为什么相同的代码在同一台计算机上的执行时间可能不同?

    我是 C 编程新手 我编写了代码并希望获得它的运行时 这就是我所做的 每次运行代码时 我都会得到不同的运行时值 这样对吗 或者我的代码有问题吗 int main int argc char argv time t start end sta
  • 如何在 Visual Studio 2010 中增强 XAML 设计器?

    当我使用 XAML 设计器时 进入设计器和退出设计器是如此困难和缓慢 当我这样做时 Visual Studio 卡了一段时间 有什么方法可以增强 XAML 设计器和编辑器吗 Ant 保存 XAML 文件时非常慢 这通常意味着您可能有复杂的
  • C++ 中本地类中的静态成员变量?

    我知道我们不能宣布static本地类中的成员变量 但其原因尚不清楚 那么请问有人可以解释一下吗 另外 为什么我们不能访问非static函数内部定义的变量 内部已经定义了局部类 直接在局部类成员函数中 在下面给出的代码中 int main i
  • Unix网络编程澄清

    我正在翻阅这本经典书籍Unix网络编程 https rads stackoverflow com amzn click com 0139498761 当我偶然发现这个程序时 第 6 8 节 第 179 180 页 include unp h
  • 将内置类型转换为向量

    我的 TcpClient 类接受vector
  • 如何从 .resx 文件条目获取注释

    资源文件中的字符串有名称 值和注释 The ResXResourceReader类让我可以访问名称和值 有办法看评论吗 你应该能够得到Comment via ResXDataNode class http msdn microsoft co
  • 如何将整数转换为 void 指针?

    在 C 中使用线程时 我面临警告 警告 从不同大小的整数转换为指针 代码如下 include
  • Visual Studio 中的测试单独成功,但一组失败

    当我在 Visual Studio 中单独运行测试时 它们都顺利通过 然而 当我同时运行所有这些时 有些通过 有些失败 我尝试在每个测试方法之间暂停 1 秒 但没有成功 有任何想法吗 在此先感谢您的帮助 你们可能有一些共享数据 检查正在使用
  • 上下文敏感与歧义

    我对上下文敏感性和歧义如何相互影响感到困惑 我认为正确的是 歧义 歧义语法会导致使用左推导或右推导构建多个解析树 所有可能的语法都是二义性的语言是二义性语言 例如 C 是一种不明确的语言 因为 x y 总是可以表示两个不同的事物 如下所述
  • 使用 Moq 使用内部构造函数模拟类型

    我正在尝试模拟 Microsoft Sync Framework 中的一个类 它只有一个内部构造函数 当我尝试以下操作时 var fullEnumerationContextMock new Mock
  • 私有模板函数

    我有一堂课 C h class C private template
  • .NET中的LinkedList是循环链表吗?

    我需要一个循环链表 所以我想知道是否LinkedList是循环链表吗 每当您想要移动列表中的 下一个 块时 以循环方式使用它的快速解决方案 current current Next current List First 电流在哪里Linke
  • (de)从 CSV 序列化为对象(或者最好是类型对象的列表)

    我是一名 C 程序员 试图学习 C 似乎有一些内置的对象序列化 但我在这里有点不知所措 我被要求将测试数据从 CSV 文件加载到对象集合中 CSV 比 xml 更受青睐 因为它更简单且更易于人类阅读 我们正在创建测试数据来运行单元测试 该集
  • gcc 的配置选项如何确定默认枚举大小(短或非短)?

    我尝试了一些 gcc 编译器来查看默认枚举大小是否很短 至少一个字节 强制使用 fshort enums 或无短 至少 4 个字节 强制使用 fno short enums user host echo Static assert 4 si
  • 为什么在setsid()之前fork()

    Why fork before setsid 守护进程 基本上 如果我想将一个进程与其控制终端分离并使其成为进程组领导者 我使用setsid 之前没有分叉就这样做是行不通的 Why 首先 setsid 将使您的进程成为进程组的领导者 但它也
  • 有没有办法强制显示工具提示?

    我有一个验证字段的方法 如果无法验证 该字段将被清除并标记为红色 我还希望在框上方弹出一个工具提示 并向用户显示该值无效的消息 有没有办法做到这一点 并且可以控制工具提示显示的时间 我怎样才能让它自己弹出而不是鼠标悬停时弹出 If the
  • 编译时“strlen()”有效吗?

    有时需要将字符串的长度与常量进行比较 例如 if line length gt 2 Do something 但我试图避免在代码中使用 魔法 常量 通常我使用这样的代码 if line length gt strlen Do somethi
  • 英特尔 Pin 与 C++14

    问题 我有一些关于在 C 14 或其他 C 版本中使用英特尔 Pin 的问题 使用较新版本从较旧的 C 编译代码很少会出现任何问题 但由于 Intel Pin 是操作指令级别的 如果我使用 C 11 或 C 14 编译它 是否会出现任何不良
  • 检查Windows控制台中是否按下了键[重复]

    这个问题在这里已经有答案了 可能的重复 C 控制台键盘事件 https stackoverflow com questions 2067893 c console keyboard events 我希望 Windows 控制台程序在按下某个
  • 如何正确使用 std::condition_variable?

    我很困惑conditions variables以及如何 安全 使用它们 在我的应用程序中 我有一个创建 gui 线程的类 但是当 gui 是由 gui 线程构造时 主线程需要等待 情况与下面的函数相同 主线程创建互斥体 锁和conditi

随机推荐

  • 基于arduino的串口控制数码管(5611AH)显示数字(初学,入门级附代码)

    基于arduino的串口控制数码管 5611AH 显示数字只有干货 首先先要介绍一下数码管了 这里图片为5611AH 这种数码管主要分为共阴极和共阳极两种 这里用的是共阴极的 注意区分 话不多说 直接上图片 此图为模拟图 当然我有实物 实物
  • vs2008创建动态库和使用动态库的方法

    一 创建动态库 打开vs2008 新建一个项目 选择win32 gt 控制台应用程序 gt 输入名称 点击确定 点击下一步 选择DLL gt 勾选空项目 点击完成 至此工程创建完毕 向工程中添加 h文件 声明接口函数 声明函数前加上关键字
  • 常用几何算法

    1 矢量减法设二维矢量 P x1 y1 Q x2 y2 则矢量减法定义为 P Q x1 x2 y1 y2 显然有性质 P Q Q P 如不加说明 下面所有的点都看作矢量 两点的减法就是矢量相减 2 矢量叉积设矢量P x1 y1 Q x2 y
  • 这个高仿小米商城项目太惊艳了

    我的引语 晚上好 我是吴小龙同学 我的公众号 菜鸟翻身 会推荐 GitHub 上好玩的项目 一分钟 get 一个优秀的开源项目 挖掘开源的价值 欢迎关注我 平时总觉得还有很多事情要去做 然而当真的闲下来时却不一定去做 比如今年这个天天在家窝
  • LPMM阅读笔记

    https www cnblogs com ChipView p 9278614 html LPMM阅读笔记 第1章 引言 LPMM阅读笔记 1 写给自己 转眼间我已经工作了两年 在这两年里 为了工作需要我看了很多相关书籍 在我看书的时候都
  • Linux·软中断&tasklet

    目录 软中断 中断服务接口管理 tasklet 软中断 首先明确一个概念软中断 不是软件中断int n 总来来说软中断就是内核在启动时为每一个内核创建了一个特殊的进程 这个进程会不停的poll检查是否有软中断需要执行 如果需要执行则调用注册
  • 网络爬虫js逆向解决网站登录RSA加密问题,不使用selenium如何实现登录,session维持登录状态请求爬取

    记录中大网校破解登录后爬取的方法 案例请求地址 中大网校会员中心 登陆入口 中大网校 使用工具 打码平台 超级鹰 分析请求 分析此请求 得知没有data 保持状态登录需要服务器知道是这个用户对应请求的相应验证码 所以要用session来维护
  • Spring Boot中自定义注解

    在Spring Boot中 我们可以通过自定义注解来实现一些特定的功能 自定义注解可以让我们的代码更加简洁 易于维护 并且可以提高代码的可读性和可扩展性 本文将介绍如何在Spring Boot中自定义注解 定义注解 首先 我们需要定义一个注
  • Qt读写CSV文件的几种方式及优劣

    前言 作为一种常见的数据交换格式 CSV Comma Separated Values 文件常常用于数据导出和导入等场合 在实际开发中 我们也需要使用Qt来实现CSV文件的读写操作 本篇博客将介绍使用Qt实现CSV读写的方法 并分析每种实现
  • ttlink无线打印服务器固件,TTLINK TT-180U1打印机服务器 TCP/IP添加打印机的教程

    使用TT 180U1 LPR添加方式 本教程以打印机为兄弟HL 2140激光打印机为实例 系统为Windows 7 64位系统 打印服务器IP固定为192 168 1 220 优点 不用安装软件 打印速度快 稳定性好 可跨网段打印 缺点 只
  • Python

    实现思路 分为两部分 第一部分 获取网页上数据并使用xlwt生成excel 当然你也可以选择保存到数据库 第二部分获取网页数据使用IO流将图片保存到本地 一 爬取所有英雄属性并生成excel 1 代码 import json import
  • Windows系统安装及初步使用ImageMagick

    最近在网上搜索了很多关于 Windows系统安装及如何使用ImageMagick 的相关文章 都没有详细说明如何使用 经过自己的摸索才明白如何使用 所以今天把它记录下来 1 首先第一步肯定是去官网下载安装包 http www imagema
  • Zotero(2)---使用Sci-hub插件下载文献

    Sci hub插件配置 如果没有安装zotero可以参考https blog csdn net u011895157 article details 126144104 spm 1001 2014 3001 5501 1 首先打开zoter
  • HTML常用的标签

    目录 1 段落 行内 换行标签 2 文本样式标签 3 表格标签 4 表单标签 1 表单域 2 表单控件 5 列表标签 6 超链接标签 7 图像标签 1 段落 行内 换行标签 为了让网页的文字有条理的显示出来 HTML有 p 段落标签 和 s
  • excel中如何将3'30"格式的分秒转换成以秒为单位的数字?

    在excel中 如记录比赛成绩的格式为3 30 要转换成以秒为单位的数字 如210秒的方式 请问该如何操作 假设你的数据在A列 A1 A100 在B1输入下面的公式 然后向下填充 TEXT 00 SUBSTITUTE LEFT A1 LEN
  • C# SuperSocket利用FixedHeaderReceiveFilter或BeginEndMarkReceiveFilter进行通信

    SuperSocket 是一个轻量级 跨平台而且可扩展的 Net Mono Socket 服务器程序框架 你无须了解如何使用 Socket 如何维护 Socket 连接和 Socket 如何工作 我们可以有更多的时间用在业务逻辑上 Supe
  • 大一python作业

    1 字典操作综合练习一 定义一个字典 goods Apple 4999 华为 3600 Vivo 2999 OPPO 3200 三星 4300 向字典新增一个 小米 手机 价格为2800 将字典中 华为 品牌手机价格修改为3999 输入任一
  • 淘宝的双11、春运时的抢票、微博大V的热点新闻,Alibaba双11的高并发实战经验,被这份文档诠释的极透彻

    前言 高并发意味着大流量 需要运用技术手段抵抗流量的冲击 这些手段好比操作流量 能让流量更平稳地被系统所处理 带给用户更好的体验 我们常见的高并发场景有 淘宝的双11 春运时的抢票 微博大V的热点新闻等 除了这些典型事情 每秒几十万请求的秒
  • React中的路由懒加载是什么?原理是什么?

    React lazy 是什么 随着前端应用体积的扩大 资源加载的优化是我们必须要面对的问题 动态代码加载就是其中的一个方案 webpack 提供了符合 ECMAScript 提案 的 import 语法 让我们来实现动态地加载模块 注 re
  • C++模板 类模板成员函数类外实现 类模板分文件编写的问题与解决方法 类模板配合友元函数的类内和类外实现

    文章目录 1 类模板成员函数类外实现 2 类模板分文件编写 3 类模板友元 1 类模板成员函数类外实现 学习目标 能够掌握类模板中的成员函数类外实现 场景描述 创建一个类 类中只写函数的声明 类外写实现 template