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

【C++深入系列】:模版详解(上)

🔥 本文专栏:c++
🌸作者主页:努力努力再努力wz

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

💪 今日博客励志语录你不需要很厉害才能开始,但你需要开始才能很厉害。

★★★ 本文前置知识:

类和对象(上)

类和对象(中)

类和对象(下)


引入

那假设有这么一个场景,那么你现在要编写一个简单的程序,那么该程序实现的内容就是交换两个数,那么此时你会如何实现呢?

那么我们可以定义一个交换的_swap函数,那么这个函数就是用来实现交换两个数,但是这两个数的数据类型可以是内置类型也可以是自定义类型,那么意味着我们得利用函数的重载,编写多个同名但是参数列表不同的 _swap函数来处理多种不同数据类型的两个数的交换

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;
}
.....

那么上面的这种实现方式肯定是没问题的,但是不难会发现这里定义了的多个 _swap函数,那么它们的函数逻辑都是一样的,唯一的区别就是处理的数据类型是不同的,那么这样其实会导致代码重复以及逻辑冗余,并且假设我们 _swap函数的代码逻辑写错了,我们还得修改之前编写的所有的 _swap函数,所以还存在不好维护的问题

为了解决这个问题,如果我们可以尝试把这些重载函数的代码逻辑给提取出来,忽略其涉及到的数据的数据类型,而我们需要调用处理特定数据类型的函数的话,那么只需要套用这个代码逻辑,将其中的数据类型给替换为我们想要的目标数据类型,而这种解决方式正是c++的模版解决该问题的核心思想,那么下文我将会从模版的使用以及其相关细节等多个维度带你全面认识模版,那么相信你看完之后,一定会对模版爱不释手

什么是模版以及模版如何使用

那么从模版这个名字,就形象的告诉了它的作用,那么对于函数来说,如果该函数要对不同的数据类型应用同一套函数逻辑的话,那么我们就可以采取模版,那么将该函数的代码逻辑给提取出来,忽略其涉及到的数据的数据类型,那么所谓的忽略其涉及到的数据的数据类型,不是说模版不提供数据类型,而是说它将该函数中涉及到的数据的数据类型都用一个变量来表示,那么这个变量可以代表着任意一个数据类型比如像int,double这样的内置类型,也可以是你自己定义的自定义类型,那么说这么多,我们先来看看模版长什么样子,那么我以上文的 _swap函数为例,来看看如何定义一个 _swap函数模版:

template<typename T>
void _swap(T& a,T&b)
{T temp=a;a=b;b=a;
}

那么其中模版的定义需要用到template关键字,那么template就是模版的英文,而后面跟上的尖括号里面的内容就是数据类型,那么它用一个变量T来表示,那么这个T就代表着任意的数据类型,那么它的专业的术语叫做模版参数,其中我们可以用typename或者class来声明一个模版参数,template下面就是模版函数的定义,那么此时模版函数不关心具体处理的是什么类型的数据,并且将涉及到的数据类型都用模版参数来替代

那么知道了模版如何定义之后,我们再来看看模版是如何使用,那么还是以 _swap函数为例,那么我写了一份简单的调用 _swap函数的c++代码:

#include<iostream>
using namespace std;
template<typename T>
void _swap(T& a, T& b)
{T temp = a;a = b;b = temp;
}
int main()
{int a = 10;int b = 20;cout << "befor: a=" << a << " b=" << b << endl;_swap(a, b);cout << "after: a=" << a << " b=" << b << endl;return 0;
}

在这里插入图片描述

那么我们发现调用模版函数就和我们调用普通函数一样,在代码中直接调用即可,而这就是模版的强大之处,当我们调用模版函数时,那么编译器会根据你函数调用处识别到参数的数据类型,然后找到匹配的函数模版,由于模版定义的时候,你已经给出了该函数的完整定义,只不过不涉及到的具体的数据类型,那么这里编译器就会将T给赋予具体的含义,替换为int类型或者double类型等等,也就意味着编译器此识别到模版函数调用处涉及到的参数的数据类型,然后根据模版实例化出一份具体的函数代码实现

所以之所以我们能够像调用普通函数那样调用模版函数,是因为有一个人为我们默默承担了一切,那么这个人就是编译器,那么本来应该由我们自己去编写处理int类型的数据的 _swap函数的代码以及处理double类型的数据的 _swap函数的代码,那么这个工作都交给了编译器来完成,也就是编译器在编译阶段会根据你调用该模版函数传的具体的参数的数据类型,然后它自己根据模版生成一份该函数的代码

所以总而言之,模版就是一个蓝图,那么编译器就像一个建筑师,那么它手上持有了这份蓝图,那么编译器会根据模版函数调用处传递的参数的类型,来根据蓝图建造出不同的房子,那么这就是模版,那么模版的出现就体现了一个泛型编程的思想,所谓的泛型编程就是编写独立于数据类型的代码

模版的相关细节补充

1.template关键字

那么我们知道了模版函数如何定义以及如何调用之后,那么有的小伙伴可能对于template关键字的使用不是特别熟悉,假设有这么一个场景,那么有个小伙伴想要定义两个模版函数,比如一个是上文所说的用于交换两个数的 _swap函数,另一个则是用于比较两个数大小的 _max函数,那么此时它采取的是这种方式定义模版函数的:

template<typename T>
void _swap(T& a, T& b)
{T temp = a;a = b;b = temp;
}
T _max(T&a,T&b)
{return a>=b? a: b;    
}

那么你觉得上面小伙伴这种定义的方式对吗?那么接下来我通过代码来验证一下:

#include<iostream>
using namespace std;
template<typename T>
void _swap(T& a, T& b)
{T temp = a;a = b;b = temp;
}
T _max(T& a, T& b)
{return a >= b?a : b;
}
int main()
{int a = 10;int b = 20;cout << "max :" << _max(a, b) << endl;return 0;
}

在这里插入图片描述

那么根据运行结果我们知道这么定义是错的,那么我猜这么定义的小伙伴心里面想的就是我在template关键字下面定义两个模版函数,那么这两个模版函数都会采取用上面template关键字后面的同一个模版参数,那么如果有的小伙伴是怎么想的话,那么我想说,你还是把编译器想的太天真了

根据编译器报的错误,那么我们可以发现template作用或者说修饰的范围只能是它下面接挨着的函数或者我们后文说道的类(类也可以定义为模版),那么此时编译器就把你后面定义的 _max当做一个普通的全局函数的定义来处理了,而这里我们没有所谓的T的内置类型,并且我们在代码中也没有定义所谓的T的类,编译器也无法将其视作自定义类型来处理,所以这里会报一个无法识别T的类型的错误,那么在编译器阶段就不会通过,所以我们还是老老实实的在定义每一个模版函数或者模版类前面加一个template关键字

正确版本:

#include<iostream>
using namespace std;
template<typename T>
void _swap(T& a, T& b)
{T temp = a;a = b;b = temp;
}
template<typename T>
T _max(T& a, T& b)
{return a >= b?a : b;
}
int main()
{int a = 10;int b = 20;cout << "max :" << max(a, b) << endl;cout << "a: " << a << " b:" << b << endl;return 0;
}

在这里插入图片描述

2.模版函数的调用机制

那么有的现在有的小伙伴可能会好奇,对于上文提到的 _swap函数,那么如果这里我定义了一个 _swap的普通函数的话,并且也定义了 _swap 的模版函数,那么我能否调用成功该 _swap函数,那么这里我首先写了一个代码来实验一下,那么这里代码的逻辑也很简单,那么就是定义了一个 _swap的模版函数以及一个处理int类型数据交换的普通函数 :

#include<iostream>
using namespace std;
template<typename T>
void _swap(T& a, T& b)
{T temp = a;a = b;b = temp;
}
void _swap(double& a, double& b)
{double temp = a;a = b;b = temp;
}
int main()
{int a = 10;int b = 20;cout << "befor: " << "a=" << a << " b=" << b << endl;_swap(a, b);cout <<"after: " << "a: " << a << " b:" << b << endl;return 0;
}

在这里插入图片描述

那么结果没有任何问题

那么我们再来简单的改变一下代码的逻辑,让其处理double类型的数据的交换:

#include<iostream>
using namespace std;
template<typename T>
void _swap(T& a, T& b)
{T temp = a;a = b;b = temp;
}
void _swap(double& a, double& b)
{double temp = a;a = b;b = temp;
}
int main()
{double a = 10.7;double b = 20.5;cout << "befor: " << "a=" << a << " b=" << b << endl;_swap(a, b);cout <<"after: " << "a: " << a << " b:" << b << endl;return 0;
}

在这里插入图片描述

发现结果也没有问题,那么我们对于第一个代码,那么我们应该知道,这里我们调用的真正的 _swap函数其实是编译器利用模版生成的 _swap函数因为没有处理int类型的普通函数,而对于第二种情况,我们可能会存有一个疑问,那么就是这里理论上编译器可以调用模版实例化生成的函数,也可以调用我们定义的普通函数,那么这里编译器的最终的行为是什么呢?那么这里我在代码中打了断点,通过调试来看看编译器此时的选择:

在这里插入图片描述

那么根据调试的结果,我们可以发现,当我们运行到 _swap函数调用处的时候,那么此时编译器调用的是我们自己定义的 _swap函数,那么这里我们就可以认识到编译器调用模版函数的机制了,那么当我们调用一个函数的时候,那么编译器此时会收集候选函数,而这里的候选函数就包括我们自己定义匹配的普通函数以及模版函数,那么这时候编译器调用的优先级肯定是优先调用参数列表最为匹配的普通函数,如果没有普通函数,但是有模版函数的话,那么此时编译器才会根据模版实例化函数,然后调用实例化后的函数

3.在调用处显示实例化

那么在上文的 _max函数的例子中,那么该函数只能处理一种数据类型,也就是 _swap函数只能处理两个相同数据类型的数的交换,但是不能处理两个数数据类型不同的情况,比如一个int类型的数与double类型的数的交换:

#include<iostream>
using namespace std;
template<typename T>
T _max(T& a, T& b)
{return a>=b ?a :b;
}
int main()
{int a=10;double b=20.8;cout<<"max: "<<_max(a,b)<<endl;return 0;
}

在这里插入图片描述

那么之所以会出现这种情况,就是因为我们定义的模版参数只有一个,那么这里编译器识别到模版函数的调用处,那么其识别到了两种不同的类型,但是按照模版函数的定义,该模版函数只能处理一种数据类型,所以它无法根据模版来实例化出函数,所以为了解决这个问题,那么第一种做法可以是定义两个模版参数,那么这样编译器就可以根据模版生成函数了

#include<iostream>
using namespace std;
template<typename T1,typename T2>
T2 _max(T1& a, T2& b)
{return a >= b ? a : b;
}
int main()
{int a = 10;double b= 20.8;cout << "max: " << _max(a, b) << endl;return 0;
}

在这里插入图片描述

那么第二种方式就是可以利用类型转换,那么为了匹配模版参数,那么这里我们可以将int类型转换为double类型,但是这里由于是传值而不是传引用,那么类型转换中间会生成临时变量,而临时变量具有常性,所以这里我们得用const引用来接收:

#include<iostream>
using namespace std;
template<typename T>
T _max(const T& a, const T& b)
{return a >= b ? a : b;
}
int main()
{int a = 10;double b= 20.8;cout << "max: " << _max((double)a, b) << endl;return 0;
}

那么还有一种方式则是在调用处显示实例化,那么所谓显示实例化,就是在调用处给编译器指定你要将该位置的调用的模版函数的模版参数给实例化成什么类型,那么编译器此时就不会关心你传递的参数的类型,而是先生成一份函数,然后再去识别类型,调用相应的匹配的函数

#include<iostream>
using namespace std;
template<typename T>
T _max(const T& a, const T& b)
{return a >= b ? a : b;
}
int main()
{int a = 10;double b= 20.8;cout << "max: " <<  _max<double>(a, b) << endl;return 0;
}

4.类模版

那么刚才讲的例子都是函数模版,那么我们类也可以支持所谓的泛型编程的思想,也就是不关心特定的数据类型,那么比如拿我们的栈来作为例子,那么我们知道我们可以将栈定义为一个类,然后采取动态数组的方式来实现,那么此时这个数组里面的元素可以是存储的是int类型,也可以存储的是double类型,那么如果没有模版的话,那么我们采取的方式就是定义两个类,那么一个类名叫stackInt对应的是存储int类型的数据的栈,还得定义一个类名为stackDouble的类对应存储double类型的数据的栈,那么这里面临的问题和上文的函数面临的问题一样,那么就是会导致代码重复并且不好维护

所以这里我们可以将栈定义成一个模版类,那么这里不关心该类中涉及到各种成员变量的数据类型以及成员函数中定义的变量的数据类型:

template<typename T>
class stack
{private:T* ptr;T top;T max_size;public:stack(int _deafult):ptr(new T[_deafult]),top(-1),max_size(_deafult){}void push(T x){if(top+1==max_size){ptr=new T[2*max_size];max_size=2*max_size;}ptr[++top]=x;}void pop(){if(top==-1){return;}top--;}bool empty(){return top==-1;}
};

那么注意我们实例化一个模版类的对象的时候,就一定要注意,对于我们自定义的类来,那么它的类型就是类名,而对于模板类来说,那么类型不在等于类名,而是类名加模版参数才是类型,那么一定要注意这点

类名<type> a;

那么编译器会根据调用的类模版以及模版参数实例化出一份类:

#include<iostream>
using namespace std;
template<typename T>
class stack
{
private:T* ptr;T top;T max_size;
public:stack(int _deafult=4):ptr(new T[_deafult]), top(-1), max_size(_deafult){}void push(T x){if (top + 1 == max_size){ptr = new T[2 * max_size];max_size = 2 * max_size;}ptr[++top] = x;}void pop(){if (top == -1){return;}top--;}bool empty(){return top == -1;}void print(){for (int i = 0;i <= top;i++){cout << "stack[i]: " << ptr[i] << " ";}cout << endl;}
};
int main()
{stack<int> a;a.push(1);a.push(2);a.push(4);a.push(5);a.pop();a.print();return 0;
}

在这里插入图片描述

结语

那么这就是本期关于模版所讲解的全部内容,那么这部分内容只是模版的一部分知识点,那么剩余知识点我打算在介绍完STL之后的模版下篇讲解,那么这部分知识就足够让我们顺利进入STL的学习,那么注意模版应用的场景一定还是类或者函数的逻辑相同,处理的数据类型不同的情况,如果函数的逻辑不同的话,那么还是得老老实实利用函数重载自己去手写几份代码

那么下一期我将讲解string,那么我会持续更新,希望你多多关注,如果本文有帮组到你的话,还请多多支持,你的支持就是我创作的最大的动力!
在这里插入图片描述

相关文章:

【C++深入系列】:模版详解(上)

&#x1f525; 本文专栏&#xff1a;c &#x1f338;作者主页&#xff1a;努力努力再努力wz &#x1f4aa; 今日博客励志语录&#xff1a; 你不需要很厉害才能开始&#xff0c;但你需要开始才能很厉害。 ★★★ 本文前置知识&#xff1a; 类和对象&#xff08;上&#xff09; …...

PyCharm Flask 使用 Tailwind CSS v3 配置

安装 Tailwind CSS 步骤 1&#xff1a;初始化项目 在 PyCharm 终端运行&#xff1a;npm init -y安装 Tailwind CSS&#xff1a;npm install -D tailwindcss3 postcss autoprefixer初始化 Tailwind 配置文件&#xff1a;npx tailwindcss init这会生成 tailwind.config.js。 步…...

设计模式每日硬核训练 Day 15:享元模式(Flyweight Pattern)完整讲解与实战应用

&#x1f504; 回顾 Day 14&#xff1a;组合模式小结 在 Day 14 中&#xff0c;我们学习了组合模式&#xff08;Composite Pattern&#xff09;&#xff1a; 适用于构建树状层级结构&#xff0c;使得“单个对象”和“对象集合”统一操作。广泛用于文件系统、UI 控件树、组织结…...

使用Service发布应用程序

使用Service发布应用程序 文章目录 使用Service发布应用程序[toc]一、什么是Service二、通过Endpoints理解Service的工作机制1.什么是Endpoints2.创建Service以验证Endpoints 三、Service的负载均衡机制四、Service的服务发现机制五、定义Service六、Service类型七、无头Servic…...

美家市场2025电视版分享码-美家市场电视直播软件分享码免费获取

美家市场2025电视版作为一款备受欢迎的应用市场&#xff0c;为用户提供了海量的电视直播软件&#xff0c;而分享码则是免费获取这些资源的重要途径。与此同时&#xff0c;乐看家桌面也是一款在智能电视领域极具特色的软件&#xff0c;它能与美家市场搭配使用&#xff0c;为用户…...

动手学深度学习:手语视频在NiN模型中的测试

前言 NiN模型是在LeNet的基础上修改&#xff0c;提出了1x1卷积层和全局平均池化层的概念&#xff0c;减少了全连接所带来的参数量很多的问题。本篇在之前代码的基础上添加了模型保存&#xff0c;loss和acc记录以及记录模型时间等功能&#xff0c;所以模型后面的代码会重新记录…...

医院数据中心智能化数据上报与调数机制设计

针对医院数据中心的智能化数据上报与调数机制设计,需兼顾数据安全性、效率性、合规性及智能化能力。以下为系统性设计方案,分为核心模块、技术架构和关键流程三部分: 一、核心模块设计 1. 数据上报模块 子模块功能描述多源接入层对接HIS/LIS/PACS/EMR等异构系统,支持API/E…...

Ubuntu命令速查

当你在Ubuntu系统中需要快速查询常用命令时&#xff0c;可以使用以下速查表&#xff1a; 列出文件和目录&#xff1a; ls切换目录&#xff1a; cd [目录路径]显示当前工作目录的绝对路径&#xff1a; pwd创建新目录&#xff1a; mkdir [目录名]删除文件或目录&#xff1a; rm […...

一次制作参考网杂志的阅读书源的实操经验总结(附书源)

文章目录 一、背景介绍二、书源文件三、详解制作书源&#xff08;一&#xff09;打开Web服务&#xff08;二&#xff09;参考网结构解释&#xff08;三&#xff09;阅读书源 基础&#xff08;四&#xff09;阅读书源 发现&#xff08;五&#xff09;阅读书源 详细&#xff08;六…...

python抓取HTML页面数据+可视化数据分析(投资者数量趋势)

本文所展示的代码是一个完整的数据采集、处理与可视化工具&#xff0c;主要用于从指定网站下载Excel文件&#xff0c;解析其中的数据&#xff0c;并生成投资者数量的趋势图表。以下是代码的主要功能模块及其作用&#xff1a; 1.网页数据获取 使用fetch_html_page函数从目标网…...

下拉框select标签类型

在我们很多页面里有下拉框的选择&#xff0c;这种元素怎么定位呢&#xff1f;下拉框分为两种类型&#xff1a;我们分别针对这两种元素进行定位和操作 select标签 &#xff1a; 通过select类处理。 非select标签 1、针对下拉框元素&#xff0c;如果是Select标签类型&#xff0c;…...

嵌入式C语言位操作的几种常见用法

作为一名老单片机工程师&#xff0c;我承认&#xff0c;当年刚入行的时候&#xff0c;最怕的就是看那些密密麻麻的寄存器定义&#xff0c;以及那些让人眼花缭乱的位操作。 尤其是遇到那种“明明改了寄存器&#xff0c;硬件就是不听话”的情况&#xff0c;简直想把示波器砸了&am…...

数据库原理及应用mysql版陈业斌实验四

&#x1f3dd;️专栏&#xff1a;Mysql_猫咪-9527的博客-CSDN博客 &#x1f305;主页&#xff1a;猫咪-9527-CSDN博客 “欲穷千里目&#xff0c;更上一层楼。会当凌绝顶&#xff0c;一览众山小。” 目录 实验四索引与视图 1.实验数据如下 student 表&#xff08;学生表&…...

【免登录ORACLE,jdk8安装包下载】jdk-8u441-windows-i586.exe和jdk-8u441-windows-x64.exe有什么区别

jdk-8u441-windows-i586.exe和jdk-8u441-windows-x64.exe主要有以下区别&#xff1a; 我用夸克网盘分享了「jdk」&#xff0c;链接&#xff1a;https://pan.quark.cn/s/c72666843e2b 适用系统架构&#xff1a; jdk-8u441-windows-i586.exe适用于32位的Windows操作系统&#x…...

Oracle日志系统之附加日志

Oracle日志系统之附加日志 在 Oracle 数据库中&#xff0c;附加日志&#xff08;Supplemental Log&#xff09;是一种增强日志记录的机制&#xff0c;用于在数据库的 redo log 中记录更多的变更信息&#xff0c;尤其是在进行数据迁移、复制和同步等任务时&#xff0c;能够确保…...

从零到一:管理系统设计新手如何快速上手?

管理系统设计是一项复杂而富有挑战性的任务&#xff0c;它要求设计者具备多方面的知识和技能&#xff0c;包括需求分析、架构设计、数据管理、用户界面设计等。对于初次接触这一领域的新手而言&#xff0c;如何快速上手并成为一名合格的管理系统设计者呢&#xff1f;本文将从管…...

Web 前端包管理工具深度解析:npm、yarn、pnpm 全面对比与实战建议

引言: 在现代web前端开发中,包管理工具的重要性不言而喻,无论是构建项目脚手架,安装ui库,管理依赖版本,还是实现monorepo项目结构,一个高效稳定的包管理工具都会大幅提升开发体验和协作效率 作为一名前端工程师,深入了解这些工具背后的机制与差异,对于提升项目可维护性和团队…...

Windows 图形显示驱动开发-WDDM 1.2功能—Windows 8 中的 DirectX 功能改进(六)

一、具有多示例抗别名示例访问权限的 UAV Direct3D 11 允许光栅化到无序访问视图&#xff0c; (UAV) 没有呈现目标视图 (RTV) /DSV 绑定。 即使 UAV 可以具有任意大小&#xff0c;实现也可以使用视区/剪刀矩形的像素尺寸来操作光栅器。 DirectX 11 硬件的示例模式仅为单个示例…...

Jenkins 多分支流水线: 如何创建用于 Jenkins 状态检查的 GitHub 应用

使用 Jenkins 多分支流水线时&#xff0c;您可以将状态检查与 GitHub 拉取请求集成。 以下是状态检查的示例 要实现这些类型的状态检查&#xff0c;您需要创建一个与 Jenkins 主实例集成的 GitHub 应用。 在本博客中&#xff0c;我们将介绍如何创建一个 GitHub 应用&#xff…...

LeeCode912. 排序数组

给你一个整数数组 nums&#xff0c;请你将该数组升序排列。 你必须在 不使用任何内置函数 的情况下解决问题&#xff0c;时间复杂度为 O(nlog(n))&#xff0c;并且空间复杂度尽可能小。 示例 1&#xff1a; 输入&#xff1a;nums [5,2,3,1] 输出&#xff1a;[1,2,3,5]示例 2…...

Maven 简介(图文)

Maven 简介 Maven 是一个Java 项目管理和构建的工具。可以定义项目结构、项目依赖&#xff0c;并使用统一的方式进行自动化构建&#xff0c;是Java 项目不可缺少的工具。 Maven 的作用 提供标准化的项目结构&#xff1a;以前不同的开发工具创建的项目结构是不一样的&#xf…...

深入规划 Elasticsearch 索引:策略与实践

一、Elasticsearch 索引概述 &#xff08;一&#xff09;索引基本概念 Elasticsearch 是一个分布式、高性能的全文搜索引擎&#xff0c;其核心概念之一便是索引。索引本质上是一个存储文档的逻辑容器&#xff0c;它使得数据能够在高效的检索机制下被查询到。当我们对文档进行…...

基于X86/RK/全志+FPGA+AI工业一体机在电力接地系统中的应用方案

随着电力技术的发展和需求增加&#xff0c;智能电网建设受到全球关注。电力五防系统建设是确保我国电力安全的核心任务&#xff0c;接地管理系统是其中的关键部分&#xff0c;对电力系统的安全、稳定和高效运行至关重要。工业一体机&#xff0c;凭借其卓越的性能、稳定性和环境…...

论文阅读:2024 arxiv AI Safety in Generative AI Large Language Models: A Survey

总目录 大模型安全相关研究&#xff1a;https://blog.csdn.net/WhiffeYF/article/details/142132328 AI Safety in Generative AI Large Language Models: A Survey https://arxiv.org/pdf/2407.18369 https://www.doubao.com/chat/3262156521106434 速览 研究动机&#x…...

JVM对象创建全过程

JVM对象创建全过程深度解析 1. 对象创建的整体流程 JVM创建对象的过程可以分为7个关键步骤&#xff0c;从类检查到内存分配&#xff0c;再到对象初始化&#xff1a; 类加载检查 → 内存分配 → 内存空间初始化 → 对象头设置 → 构造函数执行 → 栈帧引用建立 → 对象使用2.…...

ubuntu 22.04 使用ssh-keygen创建ssh互信账户

现有两台ubuntu 22.04服务器&#xff0c;ip分别为192.168.66.88和192.168.88.66。需要将两台服务器创建新用户并将新用户做互信。 创建账户 adduser user1 # 如果此用户不想使用密码&#xff0c;直接一直回车就行&#xff0c;创建的用户是没法使用用户密码进行登陆的 su - …...

蓝牙开发那些事儿12——(记一颗BLE芯片BringUp折腾过程)

1.背景 蓝牙这个系列已经很久很久没有更新了&#xff0c;感慨良多。 现在写这篇文章主要是BringUp一颗蓝牙芯片的过程中遇到了一些奇怪的问题&#xff0c;想了一些办法&#xff0c;一一克服了&#xff0c;看看对其他做蓝牙的同学有没有启发。 同时也安利一个叫做HACKRF的设备…...

从零构建 Vue3 登录页:结合 Vant 组件与 Axios 实现完整登录功能

在 Web 开发的世界里&#xff0c;登录页是用户与应用交互的第一道门槛&#xff0c;它的体验好坏直接影响着用户对整个应用的印象。本文将详细记录如何使用 Vue3、Vant 组件库和 Axios 构建一个兼具美观与实用的登录页面&#xff0c;并实现完整的登录逻辑与数据验证&#xff0c;…...

AutoSAR从概念到实践系列之MCAL篇(一)——MCAL架构及其模块详解

欢迎大家学习我的《AutoSAR从概念到实践系列之MCAL篇》系列课程,我是分享人M哥,目前从事车载控制器的软件开发及测试工作。 学习过程中如有任何疑问,可底下评论! 如果觉得文章内容在工作学习中有帮助到你,麻烦点赞收藏评论+关注走一波!感谢各位的支持! 老规矩,…...

多线程编程的简单案例——单例模式[多线程编程篇(3)]

目录 前言 1.wati() 和 notify() wait() 和 notify() 的产生原因 如何使用wait()和notify()? 案例一:单例模式 饿汉式写法: 懒汉式写法 对于它的优化 再次优化 结尾 前言 如何简单的去使用jconsloe 查看线程 (多线程编程篇1)_eclipse查看线程-CSDN博客 浅谈Thread类…...

万物互联时代,AWS IoT Core如何构建企业级物联网中枢平台?

在智能制造、智慧城市、车联网等场景爆发的今天&#xff0c;全球物联网设备数量已突破150亿台。企业如何高效管理海量设备并挖掘数据价值&#xff1f;AWS IoT Core作为亚马逊云科技推出的全托管物联网平台&#xff0c;正在为数千家企业提供设备连接、数据采集、实时分析的一站式…...

论文阅读:2023 arxiv Safe RLHF: Safe Reinforcement Learning from Human Feedback

总目录 大模型安全相关研究&#xff1a;https://blog.csdn.net/WhiffeYF/article/details/142132328 Safe RLHF: Safe Reinforcement Learning from Human Feedback https://arxiv.org/pdf/2310.12773 https://github.com/PKU-Alignment/safe-rlhf 速览 研究动机&#xff…...

链表相关算法题

小细节 初始化问题 我们这样子new一个ListNode 它里面的默认值是0&#xff0c;所以我们不能这样 如果我们为空&#xff0c;我们要返回null 节点结束条件判断&#xff08;多创建节点问题&#xff09; 参考示例3217 解析&#xff1a; 我的答案是多了一个无用节点 这是因为我每…...

招商信诺原点安全:一体化数据安全管理解决方案荣获“鑫智奖”!

近日&#xff0c;“鑫智奖 2025第七届金融数据智能优秀解决方案评选”榜单发布&#xff0c;原点安全申报的《招商信诺&#xff1a;数据安全一体化管理解决方案》荣获「信息安全创新优秀解决方案」。 “鑫智奖第七届金融数据智能优秀解决方案评选”活动由金科创新社主办&#x…...

实战篇|多总线网关搭建与量产验证(5000 字深度指南)

引言 1. 环境准备与硬件选型 1.1 项目需求分析 1.2 SoC 与开发板选型 1.3 物理接口与 PCB 设计 1.4 电源与供电保护 2. 软件架构与协议栈移植 2.1 分层架构详解 2.2 协议栈移植步骤 2.3 高可用驱动设计 2.4 映射逻辑与 API 定义 3. 开发流程与实践 3.1 敏捷迭代与里程碑 3.2 核…...

Jenkins 简易使用记录

一、Jenkins 核心功能与适用场景 核心功能&#xff1a; 持续集成&#xff08;CI&#xff09;&#xff1a;自动构建代码、运行单元测试。持续交付&#xff08;CD&#xff09;&#xff1a;自动化部署到测试/生产环境。任务调度&#xff1a;定时执行任务&#xff08;如备份、清理&…...

第十四节:实战场景-何实现全局状态管理?

React.createElement调用示例 Babel插件对JSX的转换逻辑 React 全局状态管理实战与 JSX 转换原理深度解析 一、React 全局状态管理实现方案 1. Context API useReducer 方案&#xff08;轻量级首选&#xff09; // 创建全局 Context 对象 const GlobalContext createConte…...

启动vite项目报Unexpected “\x88“ in JSON

启动vite项目报Unexpected “\x88” in JSON 通常是文件被防火墙加密需要寻找运维解决 重启重装npm install...

Jenkins 多分支管道

如果您正在寻找一个基于拉取请求或分支的自动化 Jenkins 持续集成和交付 (CI/CD) 流水线&#xff0c;本指南将帮助您全面了解如何使用 Jenkins 多分支流水线实现它。 Jenkins 的多分支流水线是设计 CI/CD 工作流的最佳方式之一&#xff0c;因为它完全基于 git&#xff08;源代…...

PHP腾讯云人脸核身获取NONCE ticket

参考腾讯云官方文档&#xff1a; 人脸核身 获取 NONCE ticket_腾讯云 前提条件&#xff0c;已经成功获取了access token。 获取参考文档&#xff1a; PHP腾讯云人脸核身获取Access Token-CSDN博客 public function getTxFaceNonceTicket($uid) {$access_token file_get_c…...

云计算(Cloud Computing)概述——从AWS开始

李升伟 编译 无需正式介绍亚马逊网络服务&#xff08;Amazon Web Services&#xff0c;简称AWS&#xff09;。作为行业领先的云服务提供商&#xff0c;AWS为全球开发者提供了超过170项随时可用的服务。 例如&#xff0c;Adobe能够独立于IT团队开发和更新软件。通过AWS的服务&…...

51单片机实验五:A/D和D/A转换

一、实验环境与实验器材 环境&#xff1a;Keli&#xff0c;STC-ISP烧写软件,Proteus. 器材&#xff1a;TX-1C单片机&#xff08;STC89C52RC&#xff09;、电脑。 二、 实验内容及实验步骤 1.A/D转换 概念&#xff1a;模数转换是将连续的模拟信号转换为离散的数字信…...

重构未来智能:Anthropic 解码Agent设计哲学三重奏

第一章 智能体进化论&#xff1a;从工具到自主体的认知跃迁 1.1 LLM应用范式演进图谱 阶段技术形态应用特征代表场景初级阶段单功能模型硬编码规则执行文本摘要/分类进阶阶段工作流编排多模型协同调度跨语言翻译流水线高级阶段自主智能体动态决策交互编程调试/客服对话 1.1.…...

MCP协议在纳米材料领域的深度应用:从跨尺度协同到智能研发范式重构

MCP协议在纳米材料领域的深度应用&#xff1a;从跨尺度协同到智能研发范式重构 文章目录 MCP协议在纳米材料领域的深度应用&#xff1a;从跨尺度协同到智能研发范式重构一、MCP协议的技术演进与纳米材料研究的适配性分析1.1 MCP协议的核心架构升级1.2 纳米材料研发的核心挑战与…...

.NET Core 服务实现监控可观测性最佳实践

.NET Core 概述 .Net Core 是一个开源的、跨平台的高性能框架&#xff0c;由微软开发并维护&#xff0c;现由 .NET Foundation 提供支持。它用于构建现代化、可扩展的云端和本地应用程序&#xff0c;支持开发 Web 应用、微服务、API、物联网应用以及移动后端服务&#xff0c;是…...

ios精灵脚本辅助软件,有根和无根roothide越狱区别

最新版本的ios按键精灵app 支持到15-16系统&#xff0c;可以在半越狱环境下和无根越狱环境安装&#xff0c;对于很多用户一直不理解有根和无根之间的差别&#xff0c;今天简单介绍下 最高权限和部分权限的区别 1、有根越狱 – 有系统根目录读写权限&#xff08;通过越狱软件可…...

ChatGPT-o3辅助学术大纲效果如何?

目录 1 引言 2 背景综述 2.1 自动驾驶雷达感知 2.2 生成模型演进&#xff1a;从 GAN 到 Diffusion 3 相关工作 3.1 雷达点云增强与超分辨率 3.2 扩散模型在数据增广中的应用 4 方法论 4.1 问题定义与总览 4.2 数据预处理与雷达→体素表示 4.3 潜在体素扩散网络&…...

PyCharm 2024.3.5 状态栏添加前进后退按钮

操作路径&#xff1a;Appearance & Behavior -> Menu and Toolbars -> Main Toolbar -> Left -> Add… 按钮位置&#xff1a;Main Menu -> Navigate -> OK 最终效果...

【CPP】死锁产生、排查、避免

一、死锁产生 死锁是指两个或多个线程互相等待对方释放资源&#xff0c;导致程序无法继续执行的现象。在多线程编程中&#xff0c;死锁是一种常见且严重的并发问题。死锁产生必须要四个条件同时满足才会发生&#xff1a; 互斥条件&#xff1a;某些资源只能由一个线程占用。占…...

深入理解 Android Handler

一、引言 Handler 在安卓中的地位是不言而喻的&#xff0c;几乎维系着整个安卓程序运行的生命周期&#xff0c;但是这么重要的一个东西&#xff0c;我们真的了解它吗&#xff1f;下面跟随着我的脚步&#xff0c;慢慢揭开Hanler的神秘面纱吧&#xff01; 本文将介绍Handler 的运…...