C++之泛型编程

2023-10-27

目录

模板

模板的特点

函数模板

前言

函数模板的使用方式

函数模板具体案例

使用模板的注意事项

普通函数与函数模板间的区别

具体案例

普通函数与函数模板调用规则

模板的局限性

具体化模板

类模板

前言

类模板与函数模板的区别

类模板中成员函数创建时机

类模板对象做函数的参数

传入方式

具体案例

类模板与继承

前言

子类指定具体类型案例

子类不指定具体类型案例

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

类模板分文件编写

1.直接包含源文件

2.将.h和.cpp文件中的内容写到一起,后将后缀名改为.hpp文件

类模板与友元

模板

前言:

  • C++中相对于面向对象的另一种编程思想就是泛型编程,主要利用的技术就是模板
  • C++提供了两种模板机制(函数模板和类模板)

概念:模板就是建立通用的模具,大大提高复用性

模板的特点

  • 模板不可以直接使用,它只是一个框架
  • 模板通用性很强,但是并不是万能的

使用模板的目的:提高复用性,将类型参数化 

函数模板

前言

作用:建立一个通用函数,其函数返回值类型和形参类型可以不具体制定,用一个虚拟的类型来代表

语法:

//声明一个模板,告诉编译器后面代码中紧跟着的T不要报错,T是一个通用的数据类型
template<typename T>
函数声明或函数定义

解释:

  • template:声明创建模板
  • typename:表明其后面的符号为一种数据类型(该关键字也可以用class代替)
  • T:通用的数据类型;名称可以替换,通常为大写字母。

函数模板的使用方式

  • 自动类型推导:向交换模板函数中传递的参数的类型会被自动解析
  • 显示指定类型:指定模板的具体数据类型

函数模板具体案例

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;
//函数模板
template <typename T>
//通用交换函数模板
void mySwap(T& a, T& b) {
	T temp = a;
	a = b;
	b = temp;
}
void main() {
	int a = 10;
	int b = 20.0;
	//自动类型推导(a和b的数据类型会被自动解析)
	mySwap(a, b);
	cout << "a:" << a << "\tb:" << b << endl;
	//显式指定类型(<int>为模板参数)
	mySwap<int>(a,b);
	cout << "a:" << a << "\tb:" << b << endl;
}

使用模板的注意事项

  • 在函数中,若多个参数使用模板,那么自动类型推导必须推导出一致的数据类型才可以使用
  • 模板必须确定出T的数据类型才可以使用

普通函数与函数模板间的区别

普通函数调用时可以发生自动类型转换(隐式类型转换);函数模板调用时,若利用自动类型推导,则不会发生隐式类型转换,但若利用显式指定类型的方式则可以发生隐式类型转换

具体案例

#include <iostream>
using namespace std;
template <typename T>
T myAdd(T a, T b) {
	return a + b;
}
void main() {
	int a = 10;
	char c = 'c';
	//自动类型推导
	//cout << myAdd(a, c) << endl;//报错,参数类型的指定必须一致,不能自动类型转换
	//隐式指定类型
	cout << myAdd<int>(a, c) << endl;
	//明确说明T的类型为int,传入的参数是int类型直接传,不是int类型则使用隐式类型转换转为int类型
}

普通函数与函数模板调用规则

1.若函数模板与普通函数都可以调用,则优先调用普通函数

void myPrint(int a, int b) {
	cout << "调用普通函数" << endl;
}
template <typename T>
void myPrint(T a, T b) {
	cout << "调用函数模板" << endl;
}
void main() {
	int a = 10;
	int b = 20;
	myPrint(a, b);//调用普通函数
}

2.可以通过空模板参数列表的方式来强制调用函数模板

//只写了函数声明,没写函数实现
void myPrint(int a, int b);
template <typename T>
void myPrint(T a, T b) {
	cout << "调用函数模板" << endl;
}
void main() {
	int a = 10;
	int b = 20;
	//通过空模板的参数列表强制调用函数模板
	myPrint<>(a, b);
}

3.模板也可以实现函数重载

template <typename T>
void myPrint(T a, T b) {
	cout << "调用函数模板1" << endl;
}
//重载函数模板
template <typename T>
void myPrint(T a, T b, T c) {
	cout << "调用函数模板2" << endl;
}
void main() {
	int a = 10;
	int b = 20;
	int c = 30;
	//调用函数模板1
	myPrint(a, b);
	//调用函数模板2
	myPrint(a, b, c);
}

4.如果函数模板可以产生更好的匹配,则优先使用函数模板

void myPrint(int a, int b) {
	cout << "调用普通函数" << endl;
}
template <typename T>
void myPrint(T a, T b) {
	cout << "调用函数模板" << endl;
}
void main() {
	char a = 'a';
	char b = 'b';
	//调用函数模板
	myPrint(a, b);
}

注意:若提供了函数模板,那么最好就不要提供普通函数,否则容易出现二义性

模板的局限性

template <class T>
void func(T a, T b) {
	a = b;
}

注意:模板并不是万能的,该模板函数有一个局限性,若传入的a和b是一个数组,那么就无法实现了

具体化模板

class Person {
public:
	Person(string name, int age) {
		this->m_Name = name;
		this->m_Age = age;
	}
	string m_Name;
	int m_Age;
};
template <class T>
bool myCompare(T& a, T& b) {
	if (a == b) {
		return true;
	}
	else {
		return false;
	}
}
//利用具体化(template<>)的Person版本来实现代码,具体化优先调用
template<> bool myCompare(Person & a, Person & b) {
	if (a.m_Age == b.m_Age && a.m_Name == b.m_Name) {
		return true;
	}
	else {
		return false;
	}
}
void main() {
	Person p1("Tom", 10);
	Person p2("Tom", 10);
	bool ret = myCompare(p1, p2);
	if (ret) {
		cout << "p1==p2" << endl;
	}
	else {
		cout << "p1!=p2" << endl;
	}
}

解释:模板的类型若为Person类型,那么自动调用具体化了的方法 

类模板

前言

作用:建立一个通用的类,类中的成员,数据类型可以不具体指定,用一个虚拟的类型来代表

语法: 

template<typename T>
类

解释:

  • template:声明创建模板
  • typename:表明其后面带符号的是一种数据类型(也可以用class替换)
  • T:通用的数据类型,名称可以替换,通常为大写字母

类模板与函数模板的区别

1.类模板没有自动类型推导的使用方式

template<class NameType,class AgeType>
class Person {
public:
	Person(NameType name, AgeType age) {
		this->m_Name = name;
		this->m_Age = age;
	}
	NameType m_Name;
	AgeType m_Age;
};
void main() {
	//类模板的使用(显式指定类型)
	Person<string, int> p("叶秋", 25);
	cout << "p的name:" << p.m_Name << endl << "p的age:" << p.m_Age << endl;
}

2.类模板在模板参数列表中可以有默认参数

//int为类模板的默认参数
template<class NameType,class AgeType=int>
class Person {
public:
	Person(NameType name, AgeType age) {
		this->m_Name = name;
		this->m_Age = age;
	}
	NameType m_Name;
	AgeType m_Age;
};
void main() {
	//类模板默认参数的使用
	Person<string> p("叶秋", 25);
	cout << "p的name:" << p.m_Name << endl << "p的age:" << p.m_Age << endl;
}

类模板中成员函数创建时机

  • 普通类中的成员函数一开始就可以创建
  • 类模板中的成员函数在调用时才可以创建

类模板对象做函数的参数

传入方式

  • 指定传入类型——直接显示对象的数据类型
  • 参数模板化——将对象中的参数变为模板进行传递
  • 整个类模板化——将这个对象类型模板化进行传递

具体案例

template<class NameType,class AgeType>
class Person {
public:
	Person(NameType name, AgeType age) {
		this->m_Name = name;
		this->m_Age = age;
	}
	void showPerson() {
		cout << "姓名:" << this->m_Name << "\t年龄:" << this->m_Age << endl;
	}
	NameType m_Name;
	AgeType m_Age;
};
//指定传入类型
void printPerson1(Person<string,int> &p) {
	p.showPerson();
}
//参数模板化
template<class T1 ,class T2>
void printPerson2(Person<T1,T2> &p) {
	p.showPerson();
}
//整个类模板化
template<class P>
void printPerson3(P &p) {
	p.showPerson();
}
void main() {
	Person<string, int> p("孙悟空", 100);
	printPerson1(p);
	printPerson2(p);
	printPerson3(p);
}

类模板与继承

前言

  • 当子类继承的父类是一个类模板时,子类在声明的时候需要指定父类的类型
  • 若不指定具体的类型,那么编译器无法给予子类分配内存
  • 若想灵活指定父类中T的类型,子类也需要变成类模板

子类指定具体类型案例

template<class T>
class Base {
	T m;
};
class Son:public Base<int> {};

子类不指定具体类型案例

template<class T>
class Base {
	T m;
};
template<class T>
class Son:public Base<T> {};

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

template<class NameType,class AgeType>
class Person {
public:
	Person(NameType name, AgeType age);
	void showPerson();
	NameType m_Name;
	AgeType m_Age;
};
//构造函数的类外实现
template<class NameType, class AgeType>
Person<NameType,AgeType>::Person(NameType name,AgeType age){
	this->m_Name = name;
	this->m_Age = age;
}
//成员函数的类外实现
template<class NameType, class AgeType>
void Person<NameType, AgeType>::showPerson() {
	cout << "姓名:" << this->m_Name << "\t年龄:" << this->m_Age << endl;
}

注意:类模板中的成员函数类外实现时需要加上模板的参数列表

类模板分文件编写

1.直接包含源文件

person.h文件内

#pragma once
#include <iostream>
using namespace std;
template<class NameType, class AgeType>
class Person {
public:
	Person(NameType name, AgeType age);
	void showPerson();
	NameType m_Name;
	AgeType m_Age;
};

person.cpp文件内

#include "person.h"
//构造函数的类外实现
template<class NameType, class AgeType>
Person<NameType, AgeType>::Person(NameType name, AgeType age) {
	this->m_Name = name;
	this->m_Age = age;
}
//成员函数的类外实现
template<class NameType, class AgeType>
void Person<NameType, AgeType>::showPerson() {
	cout << "姓名:" << this->m_Name << "\t年龄:" << this->m_Age << endl;
}

执行文件内

//这里必须包含.cpp文件方可
#include "person.cpp"
void main() {
	Person<string, int> p("lili", 18);
	p.showPerson();
}

执行文件不可以包含.h文件必须包含.cpp问件原因:类模板中的成员函数在调用时才可以创建

2.将.h和.cpp文件中的内容写到一起,后将后缀名改为.hpp文件

person.hpp文件内

#pragma once
#include <iostream>
using namespace std;
template<class NameType, class AgeType>
class Person {
public:
	Person(NameType name, AgeType age);
	void showPerson();
	NameType m_Name;
	AgeType m_Age;
};

//构造函数的类外实现
template<class NameType, class AgeType>
Person<NameType, AgeType>::Person(NameType name, AgeType age) {
	this->m_Name = name;
	this->m_Age = age;
}
//成员函数的类外实现
template<class NameType, class AgeType>
void Person<NameType, AgeType>::showPerson() {
	cout << "姓名:" << this->m_Name << "\t年龄:" << this->m_Age << endl;
}

执行文件内

//这里必须包含.hpp文件
#include "person.hpp"
void main() {
	Person<string, int> p("lili", 18);
	p.showPerson();
}

类模板与友元

1.全局函数类内实现,直接在类内声明友元即可

template<class T1,class T2>
class Person {
	//全局函数类内实现
	friend void printPerson(Person<T1,T2> p) {
		cout << "姓名:" << p.m_Name << "\t年龄:" << p.m_Age << endl;
	}
public:
	Person(T1 name, T2 age) {
		this->m_Name = name;
		this->m_Age = age;
	}
private:
	T1 m_Name;
	T2 m_Age;
};
void main() {
	Person<string, int> p("lili", 18);
	printPerson(p);
}

2.全局函数类外实现,需要让编译器知道该全局函数的存在

//编译器需要先知道printPerson函数的存在以及Person类的存在
template< class T1, class T2 >
class Person;
template<class T1, class T2>
void printPerson(Person< T1, T2 > p) {
	cout << "姓名:" << p.m_Name << "\t年龄:" << p.m_Age << endl;
}
template<class T1,class T2>
class Person {
	//全局函数类外实现
	//加空模板参数列表证明他是个模板函数
	//若全局函数是类外实现,需要让编译器提前知道这个函数的存在
	friend void printPerson<>(Person<T1, T2> p);
public:
	Person(T1 name, T2 age) {
		this->m_Name = name;
		this->m_Age = age;
	}
private:
	T1 m_Name;
	T2 m_Age;
};
void main() {
	Person<string, int> p("lili", 18);
	printPerson(p);
}

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

C++之泛型编程 的相关文章

  • Hololens 应用程序将不再构建 - 引用元数据文件丢失且找不到 c-Sharp.firstpass

    我已按照 Microsoft 在其多个项目下列出的确切步骤进行操作微软全息 学院 https developer microsoft com en us windows holographic academy教程 我完成了所有这些 并且从创
  • 创建文件并使用内存流保存到其中

    如何创建文件并使用内存流写入文件 我需要使用内存流来防止其他线程尝试访问该文件 我试图保存到文件的数据是 html 如何才能做到这一点 假设您的意思是如何将文件的内容复制到内存流 如果您使用的是框架4 var memoryStream ne
  • 如何在 ASP.Net Core 6 Web Api 中依赖注入 Microsoft Graph 客户端

    我正在尝试使用 ASP Net Core 6 设置 Web api 以便用户可以到达我的端点 然后我使用特权帐户在 Teams 中执行一些工作 我认为我没有正确连接 DI 部分 因为在向 Teams 发出请求时出现以下错误 MsalUiRe
  • ScrollableControl 在整个控件周围绘制边框

    我正在构建基于的自定义用户控件ScrollableControl 现在我正在尝试在控件周围添加边框 类似于 DataGridView 的边框 我可以使用以下方法绘制边框 e Graphics TranslateTransform AutoS
  • 如何有效地测试action是否用属性(AuthorizeAttribute)修饰?

    我正在使用 MVC 并且有一种情况OnActionExecuting 我需要确定即将执行的Action方法是否用属性修饰 AuthorizeAttribute尤其 我不是问授权是否成功 失败 而是问该方法是否需要授权 对于非 MVC 人员
  • C# SMO 远程数据库备份到本地机器

    我有一个执行 SQL 数据库备份和恢复的应用程序 这在本地计算机上运行良好 但是如果我针对另一台计算机上托管的 SQL 服务器运行此应用程序 则会出现以下错误 Microsoft SqlServer Management Smo Faile
  • 使用 R.Net 版本 1.5.5 创建 REngine 实例

    我正在尝试创建一个 Hello World 示例R Language using R Net版本1 5 5 从 NuGet 加载 不幸的是 我见过的在线示例都不起作用 这就是我所做的 已安装Microsoft R Open 3 2 4 增强
  • 合并多边形的高效算法

    我有一个多边形列表 在这个列表中 一些多边形重叠 或者接触其他多边形 我的任务是合并所有相互重叠或接触的多边形 我有一个union执行此操作的方法 做到这一点最有效的方法是什么 我目前能想到的是循环遍历多边形列表 检查合并列表以查看该多边形
  • Makefile:如何正确包含头文件及其目录?

    我有以下 makefile CC g INC DIR StdCUtil CFLAGS c Wall I INC DIR DEPS split h all Lock o DBC o Trace o o cpp DEPS CC o lt CFL
  • Magento SOAP V2 API - 附加属性设置为空

    几个小时以来 我一直在尝试通过 SOAP V2 API 创建具有附加属性的产品 每当我打电话时就会添加该产品目录产品创建但我随请求发送的附加属性被设置为空 每当我不添加附加属性时 这两个属性都会设置为其默认值 因此我认为这些属性正在发送和接
  • 如何将8字节的十六进制数输入到char数组中?

    我想生成以以下开头的十六进制数字序列07060504003020100 下一个数字是0f0e0d0c0b0a0908等等按这个顺序 当我使用unsigned long long int并输出数据的前4位 这意味着0被截断 它打印706050
  • 我们可以向 ServicePointManager.SecurityProtocol 添加四个协议吗?

    我想支持从 ssl3 到 tls 1 2 的所有安全协议 但是在网上搜索时我发现代码为 ServicePointManager SecurityProtocol SecurityProtocolType Ssl3 SecurityProto
  • 以编程方式将 UserControl 从 ContentControl 移动到另一个 ContentControl

    在 WPF 应用程序中 我想在代码中将 UserControl 从 ContentControl 移动到另一个控件 myContentControl2 Content myUserControl 在这种情况下我得到一个错误 指定的元素已经是
  • 如何通过反射获取透明代理的属性值?

    我的代码接收透明代理而不是原始实例 虽然这var type obj GetType 产生原始类的类型 下面的代码抛出TargetException 对象与目标类型不匹配 var value property GetValue obj nul
  • nVidia 和 ATI 之间的 OpenGL 渲染差异

    最近 我将 ATI 驱动程序 我使用的是 HD7970 更新为最新版本 但我的 OpenGL 项目的一些对象停止工作 更重要的是 他们适用于 nVidia 最新驱动程序 在 960m 上测试 ATI 和 nVidia 渲染管道之间有什么我应
  • GCC编译非常慢(文件大)

    我正在尝试编译一个大的 C 文件 专门用于 MATLAB mexing C 文件大约 20 MB 可用来自 GCC 错误跟踪器 https gcc gnu org bugzilla attachment cgi id 36632如果你想玩一
  • 您可以从 AuthorizeAttribute 返回 HTTP 响应而不引发异常吗?

    我在各种控制器上使用 AuthorizeAttribute 可能需要根据请求本身的某些属性返回 403 或 429 请求过多 我完全在自定义 OnAuthorization 实现中实现了它 然后在必要时抛出一个带有适当响应代码的新 Http
  • WPF - 将窗口置于前面

    我有一个 WPF 窗口 我没有关闭它 相反 我执行 Hide 和 Show 它 现在 当我双击记录上网格中的主窗口时 这将触发 Show 窗口 该窗口将始终显示在主窗口后面 我尝试过以下方法 但没有成功 view Show view Act
  • C# p/Invoke 如何使用 DirectX 游戏的 SendInput 模拟 keyPRESS 事件

    我经常为各种机器人或其他 GUI 自动化程序模拟键盘按下事件而苦苦挣扎 我已经成功地使用以下方法模拟按键事件 INPUT kInput new INPUT 1 kInput j type SendInputEventType InputKe
  • 从 C# 应用程序调用 ASP.net Web 服务

    我有个问题 我如何调用 Web 服务并从 C 桌面应用程序获取结果 我正在制作一个桌面应用程序 我希望它能够连接到我的在线 ASP net Web 服务 这怎么可能 在 解决方案资源管理器 中 右键单击项目节点并选择 添加 Service参

随机推荐

  • WebRTC视频码率控制(二)—— QP检测

    WebRTC在视频编码过程中会进行QP检测 目的是让视频质量维持在可接受范围的前提下 调节整体视频表现 如分辨率 帧率 这里要注意的是 QP检测机制只是利用QP分析结果对分辨率 帧率进行调节 并不对编码QP做直接调整 说句题外话 通常编码器
  • Hausdorff distance

    微分动力系统原理 这本书里有介绍 Hausdorff距离是描述两组点集之间相似程度的一种量度 它是两个点集之间距离的一种定义形式 假设有两组集合A a1 ap B b1 bq 则这两个点集合之间的Hausdorff距离定义为 H A B m
  • Netcat 了解

    工作项目中遇到有用Netcat来实现Windows gt Macos通信 传输文件与数据的 所以想了解一下 Netcat 简称nc 是一款简单的Unix工具 使用UDP和TCP协议 它是一个可靠的容易被其他程序所启用的后台操作工具 同时它也
  • 计算机虚拟技术有什么用途,CPU虚拟化有什么作用?CPU怎么开启虚拟化技术?

    目前Intel和AMD的主流CPU都支持虚拟化技术 而搭配的主板BIOS中都自带了开启虚拟化技术的功能 但是主板出厂时默认禁用虚拟化技术的 如果我们如果需要使用CPU虚拟化技术 那么需要在主板中开启 那么CPU怎么开启虚拟化技术 下面装机之
  • 7-20 打印九九口诀表 (格式输出)

    下面是一个完整的下三角九九口诀表 1 1 1 1 2 2 2 2 4 1 3 3 2 3 6 3 3 9 1 4 4 2 4 8 3 4 12 4 4 16 1 5 5 2 5 10 3 5 15 4 5 20 5 5 25 1 6 6 2
  • linux对磁盘的管理员权限设置,Linux系统磁盘及文件系统管理

    本节索引 一 磁盘基本概念 二 磁盘分区管理 三 文件系统管理 四 设备挂载管理 一 磁盘基本概念 设备文件 Linux中一切皆文件 open read write close 设备类型 块设备 block 存储单位 块 磁盘 字符设备 c
  • 智能学习

    智能学习 MATLAB实现基于HS和谐搜索的时间序列未来多步预测 目录 智能学习 MATLAB实现基于HS和谐搜索的时间序列未来多步预测 效果一览 基本介绍 模型描述 程序设计 参考资料 效果一览 基本介绍 使用 Harmony Searc
  • docker部署redis集群配置文件笔记

    密码 requirepass 123456 指明为主机一的从机 slaveof 192 168 0 1 6389 主从redis同步的认证密码 与连接密码同 若不需要可不用配置 masterauth 123456 最大内存 maxmemor
  • 30条值得你借鉴的好习惯

    我有幸一直能生活在比较好的圈子中 我的优秀的同学 舍友 乃至我现在创业后遇到的优秀创业者 从他们身上看到和学到一些好的习惯 我一直觉得 好的习惯 是成功和进步的重要一点 我随手总结一些给大家 零散未经排版 当然 每个人有每个人的判断 这里可
  • 学术诚信的重要性_坚守学术道德,弘扬学术诚信

    霍楷 徐晨 摘 要 学车无辕而不立 人无信则不立 诚信乃为人之根本 学术诚信是个人行为秉性和学术道德品质的展现 反映了个体真实水准与学术涵养 培养学术道德意识 弘扬学术诚信精神 坚守学术诚信理念 净化学术环境是艺术类高校义不容辞的责任 提升
  • 基础12:高阶函数

    高阶函数 高阶函数英文叫 Higher order function 它的定义很简单 就是至少满足下列一个条件的函数 接受一个或多个函数作为输入 输出一个函数 也就是说高阶函数是对其他函数进行操作的函数 可以将它们作为参数传递 或者是返回它
  • springboot项目启动成功后执行一段代码的两种方式

    转自 https www cnblogs com zuidongfeng p 9926471 html 1 实现ApplicationRunner接口 package com lnjecit lifecycle import org spr
  • netcat小工具使用

    接收端 nc l 1789 gt test1 txt 发送端 nc 1 1 1 1 1789 lt test1 txt 使用nc传文件要比scp快不少 当然 安全性低了 root 12 nc h usage nc 46DdhklnrStUu
  • 小米笔记本pro开机出现no bootable devices

    用了4个月的小米笔记本开机突然出现no bootable devices 无法正常启动 很烦 如下图 上网查了资料 说是无法正确识别硬盘 然后 小米论坛的朋友 也有反馈 说很他们的小米笔记本也都出现了类似的情况 至今没有找到解决的方法 这可
  • 51单片机AD模数转换(SPI通信)

    一 AD DA介绍 AD AnalogtoDigital 模拟 数字转换 将模拟信号转换为计算机可操作的数字信号 DA Digital to Analog 数字 模拟转换 将计算机输出的数字信号转换为模拟信号 AD DA转换打开了计算机与模
  • python pandas定位表格中的某一单元并修改——at

    python pandas定位表格中的某一单元并修改 at 首先 我们创造一个用来进行测试的dataframe import pandas data aaa abc1 abc2 bbb bc1 bc2 ccc c1 c2 df pandas
  • Nacos安装详细过程

    本文来说下Nacos 注册中心 配置中心 安装详细过程 文章目录 初识Nacos Nacos开发必知 安装Nacos 本文小结 初识Nacos Nacos 致力于帮助您发现 配置和管理微服务 Nacos 提供了一组简单易用的特性集 帮助您快
  • 【转】介绍线性代数

    color red 这里转一个别人写的对线性代数的理解 觉得他已经写出了线性代数的魂 可惜的是我也是从网上别人的转载中摘录的 未知作者的大名啊 color 今天先谈谈对线形空间和矩阵的几个核心概念的理解 这些东西大部分是凭着自己的理解写出来
  • Canvas画布基本功能及实现网页签名功能

    canvas 简介
  • C++之泛型编程

    目录 模板 模板的特点 函数模板 前言 函数模板的使用方式 函数模板具体案例 使用模板的注意事项 普通函数与函数模板间的区别 具体案例 普通函数与函数模板调用规则 模板的局限性 具体化模板 类模板 前言 类模板与函数模板的区别 类模板中成员