C++ 提高编程

C++ 提高编程
主要针对C++泛型编程和STL技术

一、 模板
1、 概念
模板就是建立通用的模具,大大提高代码的复用性

模板特点

模板不可以直接使用,它只是一个框架
​ 模板的通用并不是万能的
2、 函数模板
C++ 另一种编程思想为泛型编程,主要利用的技术就是模板
C++ 提供两种模板机制:函数模板 和 类模板
2.1 函数模板语法
函数模板的作用:建立一个通用函数,其函数返回值类型和形参类型可以不具体确定,用一个虚拟的类型来代表

语法

template<typename T>
函数声明或定义

参数

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

// 两个整型交换函数
void swap(int& a, int& b)
{int temp = a;a = b; b = temp;
}
// 交换浮点型的函数
void swap(double& a, double& b)
{double temp = a;a = b;b = temp;
}
// 函数模板
template <typename T>  // 声明模板,告诉编译器后面代码紧跟着T,不要报错,T是一个通用的数据类型
void m_swap(T& a, T& b)
{T temp = a;a = b;b = temp;
}
void test()
{int a = 1;int b = 3;double a1 = 4;double b1 = 5;/* swap(a, b);cout << a << b << endl;swap(a1, b1);cout << a1 << b1 << endl; */// 使用函数模板// 1、 自动推导m_swap(a, b);cout << a << b << endl;// 2、 显示指定类型m_swap<int>(a, b);cout << a << b << endl;
}

模板可以将数据类型参数化

模板的使用方法

自动推导
显示指定类型
2.2 注意事项
注意事项

自动推导数据类型,必须推导出一致的数据类型 T,才可以使用
模板必须要确定出 T 的数据类型,才可以使用
2.3 普通函数和函数模板的区别
普通函数调用时可以发生自动类型转换(隐式类型装换)
函数模板调用时,如果利用自动类型推导,不会发生隐式类型装换
如果利用显示指定类型的方法,可以发生隐式类型转换
2.4 普通函数和函数模板的调用规则
调用规则如下

如果函数模板和普通函数都可以实现,优先调用普通函数

可以通过空模板参数列表强制调用函数模板

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

函数模板也可以发生重载

如果函数模板可以产生更好的匹配模式,优先调用函数模板

void myPrint(int a, int b)
{cout << a << b << endl;cout << "普通函数" << endl;
}
template<typename T>
void myPrint(T a, T b)
{cout << a << b << endl;cout << "模板函数" << endl;
}void test()
{char a = 'a';char b = 'b';myPrint(a, b);  // 函数模板可以产生更好的匹配 
}

既然提供了函数模板,最好不要提供普通函数,否则容易出现二义性

2.5 模板的局限性
模板的通用性并不是万能的
如果传入的是一个元组以及自定义数据类型,就无法实现了

因此,C++为了解决这种问题,提供模板的重载,可以为这些特定的类型提供具体化模板

// 模板重载
// 对比两个数据是否相等
class Person
{
public:Person(string name, int age){m_Age = age;m_Name = name;}string m_Name;int m_Age;
};
template<class T>
bool myCompare(T& a, T& b)  // 如果传入的是一个自定义数据类型呢
{if (a == b){return true;}else{return false;}
}
// 利用具体化Person的版本实现代码,具体化优先调用
// 也可以使用运算符重载
template<>bool myCompare(Person& p1, Person& p2)
{if (p1.m_Name == p2.m_Name && p1.m_Age == p2.m_Age){return true;}else{return false;}
}
void test()
{Person p1("Tom", 10);Person p2("Tom", 10);cout << myCompare(p1, p2) << endl;
}

学习模板并不是为了写模板,而是在STL中能够运用系统提供的模板

3、 类模板
3.1 类模板语法
类模板作用

建立一个通用类,类中成员数据类型可以不具体制定,用一个虚拟的类型代表
语法

template<typename T>
参数template:声明创建模板
typename:表明其后面的符号是一种数据类型,可以用class来代替
T:通用的数据类型,名称可以替换,通常为大写字母
template<typename NameT, typename AgeT>
class Person
{
public:Person(NameT name, AgeT age){m_Age = age;m_Name = name;}NameT m_Name;AgeT m_Age;
};
void test()
{Person<string, int>("Tom", 30);  // 调用-只有一种调用方式
}

3.2 类模板和函数模板的区别
类模板与函数模板区别主要有两点

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

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

template<typename NameT, typename AgeT = int>  // 默认参数
class Person
{
public:Person(NameT name, AgeT age){m_Age = age;m_Name = name;}NameT m_Name;AgeT m_Age;
};
void test()
{Person<string>("Tom", 30);
}

3.3 使用时机
类模板中成员函数和普通类中成员函数创建时机是有区别的

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

class Person1
{
public:void show(){cout << "Person1" << endl;}};template<typename T>
class Person
{
public:// 没调用,其不会编译,因为无法确定T的数据类型T p1;void func1(){p1.show();}};
void test()
{Person<Person1> p;p.func1();
}

3.4 类模板对象函数做参数
类模板实例出的对象,向函数传参

一共有三种传入方式

指定传入的数据类型:直接显示对象的数据类型

// 类模板做函数的参数
template<class T1, class T2>
class Person
{
public:Person(T1 name, T2 age){m_Name = name;m_Age = age;}T1 m_Name;T2 m_Age;void showPerson(){cout << "name:" << m_Name << " age:" << m_Age << endl;}
};
// 指定传入类型
void printPerson1(Person<string, int> &p)  
{p.showPerson();
}
// 参数模板化
template<class T1, class T2>
void printPerson2(Person<T1, T2>& p)
{p.showPerson();cout << "T1的类型为:" << typeid(T1).name() << endl;cout << "T2的类型为:" << typeid(T2).name() << endl;
}
// 整个类模板化
template<class T>
void printPerson3(T &p)
{p.showPerson();
}
void test()
{Person<string, int> p("Tom", 12);printPerson1(p);printPerson2(p);printPerson3(p);
}

二、 STL 初识
1、 基本概念
STL 基本模板库
STL 从广义上分为容器、算法和迭代器
容器和算法事件通过迭代器无缝连接
STL 几乎所有的代码都采用了模板类或模板函数
2、 STL 六大组件
STL 大体分为六大组件:容器、算法、迭代器、仿函数、适配器(配接器)、空间配置器

容器:各种数据结构:vector、list、deque、set、map等,用来存放数据
算法:各种常用的算法,如sort、find、copy、for_each等
迭代器:扮演了容器和算法之间的胶合剂
仿函数:行为类似的函数,可作为算法的某种策略
适配器:一种用来修饰容器或者仿函数或迭代器接口的东西
空间配置器:负责空间的配置和管理
2.1 容器、算法、迭代器
容器:置物之所也

STL 容器就是将运用最广泛的一些数据结构实现出来

常用的数据结构:数组、列表、树、栈、队列、集合、映射表等

这些容器分为序列式容器和关联式容器两种

序列式容器:强调值的排序,序列式容器中的每个元素均有固定的位置
关联式容器:二叉树结构,各元素之间没有严格的物理上的顺序关系
算法:问题之解也

有限的步骤,解决逻辑或数学上的问题,这叫做算法

算法分为:质变算法和非质变算法

质变算法:是指运算过程中会更改区间内的元素的内容,例如拷贝、替换、删除等等
非质变算法:是指运算过程中不会更改区间内的元素内容,例如查找、计数、遍历、寻找极值等等
迭代器:容器和算法之间粘合剂

提供一种方法,使之能够依序寻访某个容器所含有的各个元素,而又无需暴露该容器的内部表示方式

每个容器都有自己专属的迭代器

迭代器使用非常类似于指针

迭代器种类
在这里插入图片描述
常用的容器中迭代器种类为双向迭代器和随机访问迭代器

3、 迭代器初始
3.1 vector 存放内置数据类型
容器:vector

算法:for_each

迭代器:vector::iterator

#include <vector>  // vector 头文件
#include <algorithm>  // 标准算法头文件void printVector(int value)
{cout << value << endl;
}
// vector 存放内置数据类型
void test()
{// 创建一个 vector 容器——数组vector<int> v;// 向容器中插入数据v.push_back(10);  // 尾插数据v.push_back(11);v.push_back(12);// 通过迭代器访问容器中的数据vector<int>::iterator itBegin = v.begin(); // 起始迭代器,指向容器中第一个元素,当做指针使用vector<int>::iterator itEnd = v.end();  // 结束迭代器,指向容器最后一个元素的下一个位置// 第一种遍历方式while (itBegin != itEnd){cout << *itBegin << endl;itBegin++;}// 第二种遍历方式for (vector<int>::iterator it = v.begin(); it != v.end(); it++){cout << *it << endl;}// 第三种遍历方式for_each(v.begin(), v.end(), printVector);  // 回调函数
}

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

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

相关文章

Ubuntu搭建Samba服务-学习记录

文章目录 Ubuntu安装Samba流程Samba配置文件Samba添加账户配置文件修改Samba服务控制设置开机自动启动通过systemctl 启动服务通过 rc.local 启动 Windows访问参考链接 当前文章仅用于记录&#xff0c;在 Ubuntu中安装使用Samba&#xff0c;在Windows访问 系统环境&#xff1a;…

【问题记录】Ubuntu 22.04 环境下,程序报:段错误(核心已转储)怎么使用 core 文件和GDB调试器 解决?

目录 环境 问题情况 解决思路 原因分析 解决方法 番外知识 环境 VMware Workstation 16 Pro &#xff08;版本&#xff1a;16.1.2 build-17966106&#xff09;ubuntu-22.04.2-desktop-amd64 问题情况 本人在运行百万并发的服务端程序时&#xff0c;程序运行报&#xff1a…

VLAN---虚拟局域网

VLAN— 虚拟局域网 LAN—局域网 MAN—城域网 WAN—广域网 1.一个VLAN相当于是一个广播域 VLAN—通过路由器和交换机协同工作后&#xff0c;将原本的一个广播域逻辑上&#xff0c;拆 分为多个虚拟的广播域。 VLAN配置&#xff1a; 1.创建VLAN VID—VLAN ID------用来区分和…

浅谈能源管理系统在水泥行业中设计分析

安科瑞 华楠 摘要&#xff1a;水泥企业作为我国产业结构中重要的耗能产业&#xff0c;同时对环境的污染也比较大&#xff0c;因此在水泥企业中建立能源管理系统&#xff0c;对水泥企业的生产过程过程进行全过程的监控和管理&#xff0c;对于降低企业的能源消耗和提高企业的经济…

【Ajax】笔记-Axios与函数发送AJAX请求

Axios 和 Ajax 的区别 1、Axios是一个基于Promise的HTTP库&#xff0c;而Ajax是对原生XHR的封装&#xff1b; 2、Ajax技术实现了局部数据的刷新&#xff0c;而Axios实现了对ajax的封装。 优缺点&#xff1a; ajax&#xff1a; 本身是针对MVC的编程,不符合现在前端MVVM的浪潮 基…

【MySQL】之复合查询

【MySQL】之复合查询 基本查询多表查询笛卡尔积自连接子查询单行子查询多行子查询多列子查询在from子句中使用子查询 合并查询小练习 基本查询 查询工资高于500或岗位为MANAGER的雇员&#xff0c;同时还要满足他们的姓名首字母为大写的J按照部门号升序而雇员的工资降序排序使用…

性能测试Ⅱ(压力测试与负载测试详解)

协议 性能理论&#xff1a;并发编程 &#xff0c;系统调度&#xff0c;调度算法 监控 压力测试与负载测试的区别是什么&#xff1f; 负载测试 在被测系统上持续不断的增加压力&#xff0c;直到性能指标(响应时间等)超过预定指标或者某种资源(CPU&内存)使用已达到饱和状…

全志F1C200S嵌入式驱动开发(解决spi加载过慢的问题)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】 之前的几个章节当中,我们陆续解决了spi-nor驱动的问题、uboot支持spi-nor的问题。按道理来说,下面要做的应该就是用uboot的loady命令把kernel、dtb、rootfs这些文件下载到ddr,然…

WebRTC Simulcast介绍

原文地址&#x1f447; https://blog.livekit.io/an-introduction-to-webrtc-simulcast-6c5f1f6402eb/ 你想知道的关于Simulcast的一切 Simulcast是WebRTC中最酷的功能之一,它允许WebRTC会议在参与者网络连接不可预测的情况下进行扩展。在这篇文章中,我们将深入探讨Simulcas…

欧姆龙CX系列PLC串口转以太网欧姆龙cp1hplc以太网连接电脑

你是否还在为工厂设备信息采集困难而烦恼&#xff1f;捷米特JM-ETH-CX转以太网通讯处理器为你解决这个问题&#xff01; 捷米特JM-ETH-CX转以太网通讯处理器专门为满足工厂设备信息化需求而设计&#xff0c;可以用于欧姆龙多个系列PLC的太网数据采集&#xff0c;非常方便构建生…

4、非线性数据结构

上一节课我们讲了线性数据结构&#xff0c;这一节我们说下非线性数据结构。 非线性数据结构&#xff0c;从字面意思来看&#xff0c;就是指不是线性的结构。线性结构的特点是只有一个前驱和一个后继。 那么非线性结构的特点就是有多个前驱或后继了。 如果只存在一个没有前驱的…

ChatGPT是什么?ChatGPT里的G、P、T分别指什么

前言 ChatGPT是一种基于人工智能技术的聊天机器人&#xff0c;它可以模拟人们的对话方式进行自然语言交流&#xff0c;并根据用户提出的问题、需求、意愿等信息提供相关服务或回答问题。 ChatGPT的G、P、T分别指“生成式”&#xff08;Generative&#xff09;、“预训练”&…

买卖股票的最佳时机系列

//方法一 class Solution { public:int dp[100005];int maxProfit(vector<int>& prices) {//dp[i]表示前i天买入卖出的获取的最大利润//min_val表示前i-1天买入的最小值&#xff1b;dp[0]0;int min_valprices[0];for(int i1;i<prices.size();i){dp[i]max(dp[i-1],…

HikariCP连接池

HikariCP连接池 HikariCP连接池是高性能的JDBC连接池&#xff0c;官网标注的三大特点&#xff1a;快速、简单、可靠&#xff0c;性能优于其他连接池。 官网详细地说明了HikariCP所做的一些优化&#xff0c;总结如下&#xff1a; 字节码精简&#xff1a;优化代码&#xff0c;直…

Jsonp劫持

JSONP 介绍 jsonp是一种协议&#xff0c;准确的说&#xff0c;他是json的一种使用模式&#xff0c;为了解决Json受同源策略限制的问题。 基本语法 JSONP的基本语法为&#xff1a;callback({“name”:”test”, “msg”:”success”}) 常见的例子包括函数调用&#xff08;如…

mac怎么转换音频格式?

mac怎么转换音频格式&#xff1f;相信很多小伙伴都知道&#xff0c;平时我们接触到的音频格式大多是mp3格式的&#xff0c;因为mp3是电脑上最为流行的音频格式&#xff0c;不过除了mp3格式外&#xff0c;还有很多不同的音频格式&#xff0c;有时候不同网上或者不同软件上下载到…

Java开发中的分层开发和整洁架构

分层开发(横向拆分) 分层开发的概念: maven多模块开发项目管理.可以利用这种管理功能,实现一个项目的多层次模块开发–分层开发. 比如,当前项目HelloController依赖HelloService 这样做目的: 复杂开发过程.解耦(不调整依赖关系,无法解耦).分层开发(横向拆分)和纵向拆分的区别…

麒麟v10-coredns 启动失败

现象 在麒麟ARM芯片的机器上搭建k8s&#xff0c;其中的的一个组件cordons 发现启动失败&#xff0c;查看日志如下所示&#xff1a;No such device or address 问题分析 期初猜测kubelet与containerd的cgroupDriver驱动不一致导致。分别查看是一致的。没有问题。发现系统存在…

leetcode 1870. Minimum Speed to Arrive on Time(准时到达的最小速度)

需要找一个speed, 使得dist[i] / speed 加起来的时间 < hour, 而且如果前一个dist[i] / speed求出来的是小数&#xff0c;必须等到下一个整数时间才计算下一个。 speed最大不会超过107. 不存在speed满足条件时返回-1. 思路&#xff1a; 如果前一个dist[i] / speed求出来的…