04 泛型编程

1、概论

编程范式:面向过程编程、面向对象编程、泛型编程。

泛型编程:目的是编写能够适合多种数据类型的代码,而不是为每种特定的数据类型编写重复的代码。

模板是实现泛型的主要工具,主要分为函数模板和类模板。

函数模板:

T代表了任意类型。

类模板:

ATL是泛型编程的典型应用。

2、函数模板

2.1 定义和调用

#include <iostream>
using namespace std;// 函数模板
/*
template<typename T>
函数的定义
*/int addInt(int a, int b) {int c = a + b;return c;
}double addDouble(double a, double b) {double c = a + b;return c;
}//提取“公因式”
template<typename T>//加之后 T就可用
T add(T a, T b) {T c = a + b;return c;
}int main() {int a = 1, b = 2;int c = addInt(a, b);cout << c << endl;//3double aa = 1.1, bb = 1.91;double cc = addDouble(aa, bb);cout << cc << endl;//3.01c = add(a, b);//自动类型的推导cout << c << endl;//3cc = add(aa, bb);cout << cc << endl;//3.01//显示指定类型c=add<int>(a, b);cout << c << endl;cc = add<double>(aa, bb);cout << cc << endl;//3.01int n = add<char>('a', 'b');cout<<n <<endl;//值为-61?return 0;
}

2.2 与普通函数的区别

#include <iostream>
using namespace std;int addInt(int a, int b) {int c = a + b;return c;
}double addDouble(double a, double b) {double c = a + b;return c;
}
//
template<typename T>
T add(T a, T b) {T c = a + b;return c;
}int main() {int a = 1, b = 2;double d = 2.1;double c = addDouble(a, b);//隐式类型转换,a/b转换为doublecout << c << endl;//int c = add(a, d);  错误: d是double 所以 T变成int又变成double 不可以//cout << c << endl;  //自动类型推导无隐式类型转换// 函数模板的  【显式指定类型】 调用时的 【隐式类型转换】int c1 = add<int>(a, d);c1 = add<double>(a, d);return 0;
}

2.3与普通函数的调用规则

#include <iostream>
using namespace std;int add(int a, int b) {cout << "调用普通函数" << endl;return a + b;
}template<typename T>
T add(T a, T b) {cout << "调用函数模板" << endl;return a + b;
}int main() {int a = 1, b = 2;add(a, b);//优先调用普通函数//输出:调用普通函数add<int>(a, b);//调用函数模板add<>(a, b);return 0;
}

函数模板的优先调用:

#include <iostream>
using namespace std;int add(int a, int b) {cout << "调用普通函数" << endl;int c = a + b;return c;
}template<typename T>
T add(T a, T b) {cout << "调用函数模板" << endl;T c = a + b;return c;
}int main() {double a = 1, b = 2;add(a, b);//普通函数未完美匹配,编译器选择函数模板return 0;
}

2.4 多参数函数被模板

#include <iostream>
using namespace std;//template<typename T1, typename T2, typename T3>
//T1 add(T2 a, T3 b) {
//    cout << typeid(T2).name() << endl;//返回值类型无法作为推导依据
//    cout << typeid(T3).name() << endl;
//    T1 c = a + b;
//    return c;
//}template<typename T2, typename T3>
T2 add(T2 a, T3 b) {cout << typeid(T2).name() << endl;//类型?  floatcout << typeid(T3).name() << endl;//__int64T2 c = a + b;return c;
}int main() {double r = add(4.0f, 8881281881);return 0;
}
/*
1、函数模板支持多个类型参数
2、一旦有类型不能推导,就会导致编译失败
3、返回值类型无法作为推导依据
*/

3、类模板

3.1 动态数组类

#include <iostream>
using namespace std;class DynamicArray {
private:int* elements;int size;
public:DynamicArray(int n) : size(n) {elements = new int[n];//动态内存申请}~DynamicArray() {delete[] elements;//会导致内存泄露,所以要销毁}int& operator[](int index) {  //[]的运算符重载return elements[index];  //返回引用,才可以赋值}
};int main() {int n = 10;// int a[n];错误int* p = new int[n];//实现DynamicArray da(100);da[1] = 3;//运算符重载da[9] = 4;cout << da[0] << ' ' << da[1] << endl;//-842150451 3return 0;
}

3.2 类模板的定义

#include <iostream>
using namespace std;//template<typename T>都可以
template<class T>
class DynamicArray {
private:T* elements;int size;
public:DynamicArray(int n) : size(n) {elements = new T[size];}~DynamicArray() {delete[] elements;}T& operator[](int index) {return elements[index];}
};int main() {//int n = 10;//int a[n];//int* p = new int[n];//实现类模板,代码的复用DynamicArray<double> da(100);//类模板实例化da[1] = 3.1;da[9] = 4.2;cout << da[0] << ' ' << da[9] << endl;//-6.27744e+66 4.2DynamicArray<char> dac(10);dac[0] = 'A';dac[1] = 'C';dac[2] = 'M';cout << dac[0] << dac[1] << dac[2] << endl;//ACMreturn 0;
}

3.3 成员函数

类内定义:

#include <iostream>
using namespace std;template<class T>
class DynamicArray {
private:T* elements;int size;
public:DynamicArray(int n) ; size(n) {elements = new T[n];}~DynamicArray() {delete[] elements;}T& operator[](int index) {  //return elements[index];}// 更新第 index 个索引的元素,把它的值改成 valuevoid update(int index, T value) {  //类模板的成员函数elements[index] = value;}
};int main() {DynamicArray<char> dac(100);dac[56] = 'h';dac.update(56, 'u');cout << dac[56] << endl;//ureturn 0;
}

类外定义:

#include <iostream>
using namespace std;template<class T>
class DynamicArray {
private:T* elements;int size;
public:DynamicArray(int n);~DynamicArray();T& operator[](int index);void update(int index, T value);// 更新第 index 个索引的元素,把它的值改成 value
};//类外定义成员函数
template<class T>//必加
DynamicArray<T>::DynamicArray(int n):size(n) {elements = new T[n];
}template<class T>//必加
DynamicArray<T>::~DynamicArray(){delete[] elements;
}template<class T>//必加
T& DynamicArray<T>::operator[](int index) {  //return elements[index];
}template<class T>//必加
void DynamicArray<T>::update(int index, T value) {  //类模板的成员函数elements[index] = value;
}int main() {DynamicArray<char> dac(100);dac[56] = 'h';dac.update(56, 'u');cout << dac[56] << endl;//ureturn 0;
}

创建时机:

#include <iostream>using namespace std;class Player {
public:void run() {cout << "跑步" << endl;}
};class Ball {
public:void drop() {cout << "下落" << endl;}
};template<class T>//类模板
class Test {T obj;
public:void move1() {//普通成员是在一开始就创建了,但类模板的obj.run();//成员函数会在调用时才创建}void move2() {obj.drop();}
};int main() {Test<Player> test1;test1.move1();//test1.move2()"drop": 不是 "Player" 的成员	类模板	Test<Ball> test2;// test2.move1();test2.move2();return 0;
}

3.4 类模板对象的函数传参

#include <iostream>
using namespace std;template<class NameType, class HpType>
class Hero {
public:Hero(NameType name, HpType hp) {this->m_name = name;this->m_hp = hp;}
private:NameType m_name;HpType m_hp;
};// 1、直接指定类型
void test1(Hero<string, double>& h) {}// 2、参数模板化
template<typename T1, typename T2>
void test2(Hero<T1, T2>& h) {}// 3、类模板化
template<typename T>
void test3(T& h) {}int main() {Hero<string, double> h("宋江", 100.0);test1(h);test2(h);test3(h);return 0;
} 

3.5继承

#include <iostream>
using namespace std;template<class NameType, class HpType>
class Hero {
public:Hero(NameType name, HpType hp) {this->m_name = name;this->m_hp = hp;}
private:NameType m_name;HpType m_hp;
};template<class T1, class T2, class T3>
class HeroSon : public Hero<T1, T2> {T3 a;
};int main() {return 0;
}

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

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

相关文章

【MySQL】架构

MySQL架构 和其它数据库相比&#xff0c;MySQL有点与众不同&#xff0c;它的架构可以在多种不同场景中应用并发挥良好作用。主要体现在存储引擎的架构上&#xff0c;插件式的存储引擎架构将查询处理和其它的系统任务以及数据的存储提取相分离。这种架构可以根据业务的需求和实…

(保姆级教程)CAN总线—如何使用CANoe(VN1640)的Scaner功能测量样件的波特率

1、如何找到测试入口 &#xff08;步骤1&#xff09;前置条件 连接好被测样件和VN1640&#xff0c;连接电源。 &#xff08;2&#xff09;打开CANoe工程&#xff0c;依次点击Hardware--》NetworkHardware&#xff0c;如下图&#xff1a; &#xff08;3&#xff09;单击Netwo…

使用 PIC 微控制器和 Adafruit IO 的基于 IoT 的 Web 控制家庭自动化

使用 PIC 微控制器和 Adafruit IO 的基于 IoT 的 Web 控制家庭自动化 家庭自动化一直是我们大多数人的灵感来源。从我们舒适的椅子或任何房间的床上切换交流负载,而无需伸手去触碰另一个房间的开关,听起来很酷,不是吗!.现在,在物联网时代,多亏了 ESP8266 模块,它使从世界…

MySQL原理:逻辑架构

目的&#xff1a;了解 SQL执行流程 以及 MySQL 内部架构&#xff0c;每个零件具体负责做什么 理解整体架构分别有什么模块每个模块具体做什么 目录 1 服务器处理客户端请求 1.1 MySQL 服务器端逻辑架构说明 2 Connectors 3 第一层&#xff1a;连接层 3.1 数据库连接池(Conn…

Excel Script Lab学习笔记

注意 The Excel JavaScript API 没有“Cell”对象或类。 相反&#xff0c;Excel JavaScript API 将所有 Excel 单元格定义为 Range 对象。 Excel UI 中的单个单元格转换为 Excel JavaScript API 中包含一个单元格的 Range 对象。 单个 Range 对象也可以包含多个连续的单元格。…

【第14节】windows sdk编程:进程与线程介绍

目录 一、进程与线程概述 1.1 进程查看 1.2 何为进程 1.3 进程的创建 1.4 进程创建实例 1.5 线程查看 1.6 何为线程 1.7 线程的创建 1.8 线程函数 1.9 线程实例 二、内核对象 2.1 何为内核对象 2.2 内核对象的公共特点 2.3 内核对象句柄 2.4 内核对象的跨进程访…

数据结构中的引用管理对象体系

数据结构中的引用管理对象体系 &#xff08;注&#xff1a;似复刻变量即实例对象&#xff09; 引用管理对象的&#xff0c;有引用就能管理到它所指向的对象&#xff0c;我们拿引用最终的目的就是管理那些我们需要管理的最终直接对象&#xff0c;引用也是对象&#xff0c;同时…

Java 异常处理

一、引言 在 Java 编程中,异常处理是一个至关重要的部分。程序在运行过程中可能会遇到各种意外情况,如文件不存在、网络连接中断、数组越界等。如果不进行适当的处理,这些异常可能会导致程序崩溃,影响用户体验。Java 提供了一套完善的异常处理机制,允许开发者捕获和处理这…

数据驱动进化:AI Agent如何重构手机交互范式?

如果说AIGC拉开了内容生成的序幕&#xff0c;那么AI Agent则标志着AI从“工具”向“助手”的跨越式进化。它不再是简单的问答机器&#xff0c;而是一个能够感知环境、规划任务并自主执行的智能体&#xff0c;更像是虚拟世界中的“全能员工”。 正如行业所热议的&#xff1a;“大…

skywalking微服务链路追踪

是什么&#xff1f; skywalking是一个优秀的国产开源框架&#xff0c;2015年由个人吴晟&#xff08;华为开发者&#xff09;开源 &#xff0c; 分布式链路追踪就是将一次分布式请求还原成调用链路&#xff0c;将一次分布式请求的调用情况集中展示&#xff0c;比如各个服务节点…

DR-CAN 卡尔曼滤波笔记

Kalman Filter&#xff08;卡尔曼滤波&#xff09; Optimal(最优化) Recursive(递归) Data Processing(数据处理) Algorithm(算法) 1 递归算法_Recursive Alorithm 1.1 公式推演 1.2 案例 1.3编程实现 % 设置迭代次数 n 5000000;% 生成测量值序列 % rand(n 1, 1) 生成一个…

HyperAD:学习弱监督音视频暴力检测在双曲空间中的方法

文章目录 速览摘要1. 引言2. 相关工作弱监督暴力检测双曲空间中的神经网络 3. 预备知识双曲几何切空间&#xff08;Tangent Space&#xff09;指数映射与对数映射&#xff08;Exponential and Logarithmic Maps&#xff09;3.1 双曲图卷积网络&#xff08;Hyperbolic Graph Con…

Freeze-Omni:冻结 LLM,实现语音对话

写在前面:语音LLM 大型语言模型(LLM)的强大能力,为构建智能语音对话系统提供了无限可能。然而,将 LLM 与语音模态结合,并非易事。直接微调 LLM,容易导致灾难性遗忘,丧失其原有的知识和能力;而训练数据不足,又难以充分发挥 LLM 的潜力。 如何才能在保留 LLM 强大能力…

践行健康养生,拥抱美好人生

在当今快节奏的社会浪潮中&#xff0c;人们在忙碌奔波时&#xff0c;健康常被抛诸脑后。可一旦身体亮起红灯&#xff0c;才惊觉健康无价。其实&#xff0c;只要巧妙运用养生之道&#xff0c;就能轻松守护健康&#xff0c;让生活重回正轨。 养生始于饮食。我们要巧妙搭配食物&am…

上海亚商投顾:沪指窄幅震荡 深海科技概念持续活跃

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一.市场情绪 市场全天窄幅震荡&#xff0c;三大指数涨跌互现。深海科技概念持续活跃&#xff0c;巨力索具、东方海洋、海洋…

Java 大视界 -- Java 大数据在智能体育赛事直播数据分析与观众互动优化中的应用(142)

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…

基于Spring Boot的图书管理系统的设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

SpringBoot对接DeepSeek

文章目录 Spring Boot 集成 DeepSeek API 详细步骤1. 创建API Key1.访问 [DeepSeek控制台](https://platform.deepseek.com/usage) 并登录。2.点击 Create API Key 生成新密钥。3.复制并保存密钥&#xff08;需在Spring Boot配置文件中使用&#xff09;。 2. 创建Spring Boot工…

Web 小项目: 网页版图书管理系统

目录 最终效果展示 代码 Gitee 地址 1. 引言 2. 留言板 [热身小练习] 2.1 准备工作 - 配置相关 2.2 创建留言表 2.3 创建 Java 类 2.4 定义 Mapper 接口 2.5 controller 2.6 service 3. 图书管理系统 3.1 准备工作 - 配置相关 3.2 创建数据库表 3.2.1 创建用户表…

PCAN安装驱动、使用PcanView监听发送报文

首先将PCAN插入电脑USB接口&#xff0c;winR快捷键输入compmgmt.msc&#xff0c;弹出计算机管理界面&#xff0c;装过驱动则显示PCAN-USB。未装过驱动的会显示XCAN-USB&#xff0c;按照如片步骤安装驱动&#xff0c;这里不在文字赘述。 PCAN Windows驱动下载&#xff1a; htt…