当前位置: 首页 > news >正文

C++模板初阶

希望文章能对你有所帮助,有不足的地方请在评论区留言指正,一起交流学习!

1. 泛型编程

        在C语言中由于数据类型的不同,导致需要对相同逻辑的函数编写多份,例如交换函数Swap函数;在交换的时候,需要相同类型数据才可以交换。如下:
        
#include <iostream>
using namespace std;void Swap(int& left, int& right)
{int temp = left;left = right;right = temp;
}
void Swap(double& left, double& right)
{double temp = left;left = right;right = temp;
}
void Swap(char& left, char& right)
{char temp = left;left = right;right = temp;
}
// 日期类
class Date
{
public:Date(int year = 2025, int month = 7, int day = 28):_year(year),_month(month),_day(day){}void Swap(Date&d){// 为了简化,直接调用的C++库中的交换函数 swapswap(_year, d._year);swap(_month, d._month);swap(_day, d._day);}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}
private:size_t _year;size_t _month;size_t _day;
};int main()
{// 自定义类型Date d1(2024, 8, 6);Date d2;cout << "交换前" << endl;d1.Print();d2.Print();d1.Swap(d2);//swap(d1, d2);cout << "交换后" << endl;d1.Print();d2.Print();// 内置类型int a1 = 10; int a2 = 20;cout << "交换前" << a1 << " " << a2 << endl;Swap(a1,a2);cout << "交换后" << a1 << " " << a2 << endl;double b1 = 22.22; double b2 = 33.33;cout << "交换前" << a1 << " " << a2 << endl;Swap(b1, b2);cout << "交换后" << a1 << " " << a2 << endl;return 0;
}

        上述代码中的每种数据类型就有一种交换函数,而且C++是面向对象的代码,其中的类型更多,因此引入了泛型编程的概念。

        泛型编程是一种编程范式,它允许在不指定具体数据类型的情况下编写代码,从而实现代码复用类型安全的平衡。在 C++ 中,泛型编程主要通过模板(Templates)实现,包括函数模板类模板。   

2. 函数模板

(1)函数模板介绍

        函数模板是一种能创建通用函数的工具,它可以处理不同的数据类型。借助模板参数,函数模板能够对类型进行参数化,从而实现代码的复用。        

        函数模板格式
template <typename T>
// template <typename T>
返回类型 函数名(参数列表) {// 函数体
}

        T就是模板参数,它代表着一种通用类型。在函数体中,T可以当作普通数据类型来使用。

实例:

#include <iostream>
using namespace std;
template <typename T>
void Swap( T& x,  T& y)
{T tmp = x;x = y;y = tmp;}
template <typename T>
void Func(const T& x, const T& y)
{cout << x << " " << y << endl;
}
int main()
{int a = 6;int b = 9;Func(a, b);Swap(a, b);Func(a, b);double c = 5.67;double d = 8.97;Func(c, d);Swap(c, d);Func(c, d);return 0;
}

        上述程序存在两个模板,一个模板是交换函数模板,一个输出函数模板,使用的都是一种数据类型的模板,那么多个数类型如何操作,如下

#include <iostream>
using namespace std;template <typename T1, typename T2>
T1 Add(T1& x, T2& y)  // 返回的是T1类型的数据,可以将T1/T2理解为万能的数据类型
{return x + y;
}
int main()
{int a = 2;double b = 5.67;cout << Add(a, b) << endl;cout << Add(b, a) << endl;return 0;
}

        两种类型的模板函数,其返回值是根据第一个传递过去的值来确定的,那么在定义一个模板参数的是什么情况呢?

(2)函数模板原理

        函数模板是一种参数化的函数定义,它本身并不是一个具体的函数,而是创建具体函数的蓝图。在编译器编译阶段,对于模板函数的使用,编译器会根据传入的实参类型来推演生成对应类型的函数以供调用。

        上述汇编语言采用的是交换函数中int double类型,编译器会根据传递的类型,编写不同类型的函数。

(3)模板实例化

        模板实例化是 C++ 编译过程中将函数模板或类模板转换为具体函数或类的核心机制。分为隐式实例化和显示实例化。

隐式实例化让编译器根据实参推演模板参数的实际类型;如下:

template <typename T>
T Add(T& x, T& y)  // 返回的是T1类型的数据,可以将T1/T2理解为万能的数据类型
{return x + y;
}
int main()
{int x1 = 5;int y1 = 8;cout << Add(x1, y1) << endl;double x2 = 5.7;double y2 = 8.9;cout << Add(x2, y2) << endl;return 0;
}
cout << Add(x1, y2) << endl;

上述代码中只有一种参数类型模板,但是匹配的是两种数据类型,一种方法就是强制转换如下:

    cout << Add((double)x1, y2) << endl; //强制转换会产生中间变量(具有常性),形参加上constcout << Add(x1, (int)y2) << endl;

还有一种方法就是显示实例化,直接告诉编译器,要转换那种类型。

显示实例化

    cout << Add<int>(x1, y2) << endl;cout << Add<double>(x1, y2) << endl;

一般情况下均是隐式实例化。

(4)模板参数的匹配原则

  1. 对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模板产生出一个实例。

  2. 如果模板可以产生一个具有更好匹配的函数, 那么将选择模板。一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数。

  3. 模板函数不允许自动类型转换,但普通函数可以进行自动类型转换;也就是不能存在隐式类型转换。

3. 类模板

        类模板是 C++ 泛型编程的核心机制,允许创建通用类以支持多种数据类型。
(1)模板形式
template<class T1, class T2, ..., class Tn>
class 类模板名
{// 类内成员定义
};

以栈为例:

template <typename T>
class Stack
{
public:Stack(int capacity = 10):_a((T*)malloc(sizeof(T)*capacity)), _size(0), _capacity(capacity){}private:T* _a;size_t _size;size_t _capacity;
};

        上述代码只是栈类的一部分,想要完全实现栈的模板,需要将其中的所有类型都改为T模板参数

(2)模板实例化
        类模板只能显示实例化。如下:
    Stack<int> st1;Stack<double> st2;Stack<char> st3;

注意: 模板参数的作用范围是当前函数或者当前类,跟着域走或者花括号;一个模板参数的生命周期就是一个函数模板或者一个类模板.

(3)成员函数的声明和定义
        和普通类不同的时候,将函数定义在类外部的情况是不同。模板使用 类名+<T>代替普通模板类的类名。
        模板类是没有类型的,只有在实例化之后才有类型例如Stack<int>.
        普通类的类型和类名是一样的,模板类的类名和普通类一样,但是类型不同如上。
实例:模板类的定义方式
//简单一些的函数为例子
template <typename T>
void Stack<T>::Print(const T& st)
{cout << st._size << endl;
}

http://www.xdnf.cn/news/1203931.html

相关文章:

  • C++模板进阶:从基础到实战的深度探索
  • 短剧小程序系统开发:连接创作者与用户的桥梁
  • vue3【组件封装】超级表单 S-form.vue
  • django ManyToManyField 如何添加数据
  • 多光谱相机助力第四次全国农业普查-农业用地调查
  • JAVA后端开发——“全量同步”和“增量同步”
  • 基于百度 iframe 框架与语音解析服务的数字人交互系统实现
  • Docker搭建Hadoop集群
  • Apache Ignite 的 JDBC Client Driver(JDBC 客户端驱动)
  • 基于电动自行车控制器设计方案
  • PyTorch中flatten()函数详解以及与view()和 reshape()的对比和实战代码示例
  • dapp前端⾯试题
  • 【QT搭建opencv环境】
  • <RT1176系列11>DMAMUX解读
  • Spring AI 1.0 提供简单的 AI 系统和服务
  • TS面试题
  • 分布式IO详解:2025年分布式无线远程IO采集控制方案选型指南
  • simple-mock-proxy,自动拾取后端接口数据,生成本地mock接口与数据
  • idea启动java应用报错
  • keepalived原理及实战部署
  • vue怎么实现导入excel表功能
  • 最新!Polkadot 更新 2025 路线图
  • C++-关于协程的一些思考
  • ERC20 和 XCM Precompile|详解背后技术逻辑
  • 【Kotlin】如何实现静态方法?(单例类、伴生对象、@JvmStatic)
  • Android中应用进程中Binder创建机制
  • VUE2 学习笔记11 脚手架
  • 从0到500账号管理:亚矩阵云手机多开组队与虚拟定位实战指南
  • 数据结构之顺序表链表栈
  • 分享一个脚本,从mysql导出数据csv到hdfs临时目录