C++模板(泛型)

1. 模板

1.1 知识点

模板:template

泛型编程:

是指数据的类型是广泛,任意的数据类型

模板:可以将一个函数或类描述成一个模板,例如:画画,给一个人物模型上色彩,根据用户上的色彩是什么人物显示什么样的色彩

模板分为 函数模板  和  类模板

1.1.1 注意

(1)template用于声明一个模板

(2)typename/class来声明模板形参,模板形参是指传递给该函数的参数类型(模板形参就是该函数的参数类型),指定该函数里用的模板形参的类型

(3)模板形参要与函数形参一一对应

1.2 函数模板

关键字:template、class/typename

格式:


	template   <模板形参1,模板形参2,........>函数返回值   函数名   ([参数1,参数2,.......])
	{

	}
	template   <class T1,class T2,........>函数返回值   函数名   ([参数1,参数2,.......])
	{
		
	}
	template   <typename T1,typename T2,........>函数返回值   函数名   ([参数1,参数2,.......])
	{

	}	

1.2.1 函数模板的调用

与C/C++普通函数调用一致:

隐式调用

格式:
		函数名(实参1,实参2);//隐式调用(模板形参)
例如:
		sum(10,20);

函数模板的显示调用(模板形参):

格式:
		函数名 <数据类型1,数据类型2,.......>(实参1,实参2,......);
例如:
		sum<int ,   char> (10,'a');

1.2.1.1 隐式调用

wide_practise.cpp

#include "iostream"
using namespace std;

//模板(泛型)

//声明函数模板写法1
template <class T1, class T2> void sum(T1 a,T2 b) {
	T1 m = a;
	T2 n = b;
	cout << "m= " << m << endl;
	cout << "n= " << n << endl;
}

声明函数模板写法2
//template <typename T1, typename T2> T1 sum(T1 a, T2 b) {
//	
//}
//
声明函数模板写法3
//template <typename T1, typename T2> T2 sum(T1 a, T2 b) {
//	
//}

int main()
{
	sum(10, 20);
	sum(10.2, 3.14);
	sum(10,"hello world");
	sum("hello","world");
	sum("你好",10);
	return 0;
}

1.2.1.2 显示调用

wide_practise.cpp

//模板(泛型)显示调用
//声明函数模板写法1
template <class T1, class T2> void sum(T1 a, T2 b) {
	T1 m = a;
	T2 n = b;
	cout << "m= " << m << "  n= " << n << endl;
}

int main()
{
	sum(10,20);//隐式调用
	sum<int, int>(50, 60);//显示调用
	sum<int, char>(40, 'a');
	return 0;
}

1.3.3 自定义类型调用

wide_practise.cpp
//模板(泛型)自定义类型
class People {
public:
	int num = 90;

};

//声明模板函数
template <class T1, class T2> void sum(T1 a, T2 b) {

	cout << "自定义类型的a= " << a.num << "  b= " << b << endl;
}

int main()
{
	People people;
	sum(people, 80);//隐式调用
	sum<People, int>(people, 55);//显示调用

	return 0;
}

1.4 练习

编写如下形式的模板: template <class Type>void sort(Type* A, int n, bool f)

对一个具有n个Type类型的一维数组进行排序,f伪1表示从小到大排序, f为0表示从大到小排序

要求使用快速排序

wide_test.cpp

#include "iostream"
#include <stdbool.h>
using namespace std;


//编写如下形式的模板: template <class Type>void sort(Type* A, int n, bool f)
//对一个具有n个Type类型的一维数组进行排序,f伪1表示从小到大排序, f为0表示从大到小排序
//快速排序

//使用快速排序
//将快速排序也声明为模板函数
template<class Type> void quick_sort(Type arr[],int left,int right) {

	//跳出递归的条件
	if (left>=right) {
		return;
	}

	//左右哨兵
	int l = left;
	int r = right;

	//定义基准数
	Type base = arr[left];

	while (l!=r) {
		
		//右哨兵先走,遇见比基准数小的就停下(即比基准数大就走动)
		while(l<r && arr[r]>=base) {
			r--;
		}
		//接着左哨兵走,遇见比基准数大的就停下(即比基准数小就走动)
		while (l<r && arr[l]<=base) {
			l++;
		}

		//当两个哨兵都停且没有相遇,就交换两个哨兵所指向的数据
		if (l<r) {
			Type tmp = arr[l];
			arr[l] = arr[r];
			arr[r] = tmp;
		}

	}

	//两个哨兵相遇时,使哨兵所指的数据与基准数交换
	//至此到这,交换后的基准数,左边都比自己小,右边都比自己大
	if (l==r) {
		Type tmp = arr[left];
		arr[left] = arr[r];
		arr[r] = tmp;
	}

	//进入递归
	quick_sort<Type>(arr,left,r-1);
	quick_sort<Type>(arr,r+1,right);
}

//声明模板
template<class Type> void sort(Type* arr, int n, bool f) {

	if (f) {//f为真正序排序

		//将快速排序也声明为模板函数
		quick_sort<Type>(arr,0,n-1);
	}
	else {//为假倒叙排序
		//我们现正排,然后反转数组,达到倒序排序的效果
		quick_sort<Type>(arr, 0, n - 1);

		int r = n;
		//数组反转
		for (int i = 0; i < n/2;i++) {
			Type tmp = arr[i];
			arr[i] = arr[r-1];
			arr[r-1] = tmp;
			r--;
		}
	}
	
}


int main()
{

	//传递整型
	int arr[] = { 8,4,1,2,7,13,2,4,8 }; 
	int size = sizeof(arr)/sizeof(arr[0]);
	sort<int>(arr, size, 0);
	//遍历
	for (int i = 0; i < size;i++) {
		cout << arr[i]<<" ";
	}

	cout << endl;

	//传递字符型
	char arr2[] = { 'g','c','z','f','c','a'};
	int size2 = sizeof(arr2) / sizeof(arr2[0]);
	sort<char>(arr2, size2, 1);
	//遍历
	for (int i = 0; i < size2; i++) {
		cout << arr2[i] << " ";
	}

	cout << endl;

	//传递浮点型
	double arr3[] = { 88.5,22.6,12.7,3.14,2.17,9.38 };
	int size3 = sizeof(arr3) / sizeof(arr3[0]);
	sort<double>(arr3, size3, 0);
	//遍历
	for (int i = 0; i < size3; i++) {
		cout << arr3[i] << " ";
	}

	return 0;
}

2. 类模板

2.1 知识点

关键字:template、class/typename

格式:

	template  <模板形参1 , 模板形参2,非类型形参,......> class  类名
	{
		
	};
	template  <class T1 , class T2,int  sum,......> class  类名
	{
		
	};	
	template  <typename T1 , typename T2,int  sum,......> class  类名
	{
		
	};

2.1.1 注:

(1)class T1/T2等是模板形参,int  sum:非类型形参

非类型:是指实例化类的时候,不能传递类型,只能传递实参,非类型形参是整型int\short\long等等不能字符串或浮点型

2)<>里的class用于声明模板形参 ,  类名前的class用于声明一个类

2.2 举例

lei_template.cpp

#include "iostream"
using namespace std;

//声明模板类
//sum 这里的sum是非类型实参,传递时不能传递类型,要传递具体的值
template<class T1, class T2,int sum> class Animal {
public:
	Animal(T1 a,T2 b) {
		this->a = a;
		this->b = b;

	}
	void diplay() {
		cout << "a= " << a << " b= " << b << endl;
	}

	T1 a;
	T2 b;
	int arr[sum];//我们利用非类型实参,给这个数组属性定义大小
};

int main()
{
	//实例化类模板
	Animal<int, char,30> animal(10, 'v');
	animal.diplay();

	return 0;
}

2.3 练习

2.3.1 例1

我在一个类中定义了一个结构体,我在类中写了一个成员函数,返回值是结构体类型,我在主函数中使用此成员函数,该怎么接收返回值呢

test.cpp
#include <iostream>
using namespace std;

class MyClass {
public:
    // 定义一个结构体类型
    struct MyStruct {
        int data;
    };

    // 返回结构体类型的成员函数
    MyStruct getStruct() {
        MyStruct result;//定义结构类型
        result.data = 42;//给结构体属性赋值
        return result;//返回结构体类型
    }
};

int main() {
    // 实例化类对象
    MyClass myObject;

    // 调用成员函数并接收返回值
    // MyClass::MyStruct 访问嵌套的结构体类型
    //  MyClass::MyStruct 这种语法对于访问嵌套类型、静态成员或命名空间中的元素是很常见的。
    MyClass::MyStruct receivedStruct = myObject.getStruct();

    // 输出结构体成员的值
    cout << "Data in MyStruct: " << receivedStruct.data << endl;

    return 0;
}

2.2.2 例2

我的写法

定义一个堆栈类模板,实现不同数据类型数据的入栈和出栈操作,堆栈的大小用非类型参数指定。

lei_template_test.cpp

#include "iostream"
#include<stdbool.h>
using namespace std;

typedef bool status;
#define MAXSIZE 10
//定义一个堆栈类模板,实现不同数据类型数据的入栈和出栈操作,堆栈的大小用非类型参数指定。

//定义模板类
template<class T> class Stack_ {
public:

	struct Stack {
		T stack[MAXSIZE];
		int top;
	};

	//创建顺序栈
	struct Stack* Stack_Create() {
		struct Stack* p = (struct Stack*)malloc(sizeof(struct Stack));
		if (p == NULL) {
			return NULL;
		}

		//赋初值
		memset(p->stack, 0, sizeof(p->stack));
		p->top = -1;
		return p;

	}

	//入栈
	status Stack_Push(struct Stack* p, T data) {
		//判断栈是否满了
		if (p->top == MAXSIZE - 1) {
			printf("栈已满,入栈失败\n");
			return false;
		}

		p->top += 1;
		p->stack[p->top] = data;
		return true;
	}

	//出栈
	status Stack_Pop(struct Stack* p, T* data) {
		//判断栈是否为空
		if (p->top == -1) {
			printf("栈为空栈,出栈失败!\n");
			return false;
		}

		*data = p->stack[p->top];
		p->stack[p->top] = 0;//清空
		p->top--;
		return true;
	}

	//遍历栈
	status Stack_Travel(struct Stack* p) {
		//判断栈是否为空
		int top_1 = p->top;

		if (top_1 == -1) {
			printf("栈为空栈,遍历失败\n");
			return false;
		}
		while (top_1 >= 0) {
			cout << p->stack[top_1] << " ";
			top_1--;
		}
		return true;

	}

	// 释放堆栈
	void Stack_Destroy(struct Stack* p) {
		delete p;  // 使用 delete 进行动态内存释放
	}


};


int main()
{
	//栈中存入int类型
	//实例化类模板
	Stack_<int> stack_;
	Stack_<int>::Stack* p = stack_.Stack_Create();//Stack_<int>::Stack是在 C++ 中使用模板类 Stack 时访问内部嵌套结构 StackStruct 的方法。
	//入栈
	stack_.Stack_Push(p, 10);
	stack_.Stack_Push(p, 20);
	stack_.Stack_Push(p, 30);
	stack_.Stack_Push(p, 40);
	stack_.Stack_Push(p, 50);
	//遍历
	stack_.Stack_Travel(p);
	cout << endl;
	//出栈
	int data;
	stack_.Stack_Pop(p, &data);
	cout << "取出栈顶元素为:" << data << endl;
	//遍历
	stack_.Stack_Travel(p);
	//释放堆栈
	stack_.Stack_Destroy(p);


	cout << endl;
	cout << endl;


	//栈中存入char类型
	//实例化类模板
	Stack_<char> stack_2;
	Stack_<char>::Stack* p2 = stack_2.Stack_Create();//Stack_<int>::Stack是在 C++ 中使用模板类 Stack 时访问内部嵌套结构 StackStruct 的方法。
	//入栈
	stack_2.Stack_Push(p2, 'a');
	stack_2.Stack_Push(p2, 'b');
	stack_2.Stack_Push(p2, 'c');
	stack_2.Stack_Push(p2, 'd');
	stack_2.Stack_Push(p2, 'e');
	//遍历
	stack_2.Stack_Travel(p2);
	cout << endl;
	//出栈
	char data2;
	stack_2.Stack_Pop(p2, &data2);
	cout << "取出栈顶元素为:" << data2 << endl;
	//遍历
	stack_2.Stack_Travel(p2);
	//释放堆栈
	stack_2.Stack_Destroy(p2);

	cout << endl;
	cout << endl;

	//栈中存入double类型
	//实例化类模板
	Stack_<double> stack_3;
	Stack_<double>::Stack* p3 = stack_3.Stack_Create();//Stack_<int>::Stack是在 C++ 中使用模板类 Stack 时访问内部嵌套结构 StackStruct 的方法。
	//入栈
	stack_3.Stack_Push(p3, 3.14);
	stack_3.Stack_Push(p3, 8.25);
	stack_3.Stack_Push(p3, 1.22);
	stack_3.Stack_Push(p3, 7.45);
	stack_3.Stack_Push(p3, 6.489523);
	//遍历
	stack_3.Stack_Travel(p3);
	cout << endl;
	//出栈
	double data3;
	stack_3.Stack_Pop(p3, &data3);
	cout << "取出栈顶元素为:" << data3 << endl;
	//遍历
	stack_3.Stack_Travel(p3);
	//释放堆栈
	stack_3.Stack_Destroy(p3);

	return 0;
}

另一种写法

lei_template_test2.cpp

#include "iostream"
using namespace std;

//定义一个堆栈类模板,实现不同数据类型数据的入栈和出栈操作,堆栈的大小用非类型参数指定。
//
template<class T, int MAXSIZE>class Stack
{
public:
	Stack()
	{
		stack = new T[MAXSIZE]{ 0 };//申请空间
		this->top = -1;
	}
	//判断栈是否为空
	bool isEmpty()
	{
		if (this->top == -1)
		{
			return true;
		}
		return false;
	}
	//判断栈是否为满
	bool isFull()
	{
		if (this->top == MAXSIZE - 1)
		{
			cout << "栈已满!" << endl;
			return true;
		}
		return false;
	}
	//入栈
	bool Push(T data)
	{
		if (this->isFull())
		{
			return false;
		}
		this->top += 1;
		this->stack[this->top] = data;
		return true;
	}
	//出栈
	bool Pop(T& data)
	{
		if (this->isEmpty())
		{
			return false;
		}
		data = this->stack[this->top];
		this->stack[this->top] = 0;
		this->top--;
		return true;
	}
	//返回栈顶元素
	bool get_Top_Data(T& data)
	{
		if (this->isEmpty())
		{
			return false;
		}
		data = this->stack[this->top];
	}
	//打印栈中的数据
	void display()
	{
		for (int i = 0; i < MAXSIZE; i++)
		{
			cout <<this->stack[i] <<" ";
		}
	}
	~Stack()
	{
		delete[]stack;//释放资源
	}
private:
	int top;//指向栈顶指针
	T* stack;
};
int main()
{
	//实例化一个类 int类型的栈
	Stack<int, 10>stack;

	//看看栈是否已满
	bool flag = stack.isFull();
	if (flag) {

	}
	else {//不满添加数据
		stack.Push(10);
		stack.Push(20);
		stack.Push(30);

		stack.display();

	}
	
	//看看栈是否为空
	flag = stack.isEmpty();
	if (flag)
	{
		cout << "栈为空!" << endl;
	}
	else
	{
		cout << endl;
		int data;
		stack.Pop(data);
		cout << "取出栈顶元素为:" << data << endl;
		stack.display();

	}

	cout << endl;
	//实例化一个类,char类型的栈
	Stack<char, 10>stack2;
	//看看栈是否已满
	bool flag2 = stack2.isFull();
	if (flag2) {

	}
	else {//不满添加数据
		stack2.Push('a');
		stack2.Push('b');
		stack2.Push('c');

		stack2.display();

	}

	//看看栈是否为空
	flag2 = stack2.isEmpty();
	if (flag2)
	{
		cout << "栈为空!" << endl;
	}
	else
	{
		cout << endl;
		char data2;
		stack2.Pop(data2);
		cout << "取出栈顶元素为:" << data2 << endl;
		stack2.display();

	}

	return 0;
}

2.2.3 使用通用模板类写一个冒泡排序

bubble_sort.cpp
#include "iostream"
using namespace std;


//使用通用模板类写一个冒泡排序
class People {
public:
	People(char c) {
		str = c;
	}

	// 重载 > 运算符
	bool operator>(const People& other) const {
		return this->str > other.str;
	}

	char str;
};

template<class T> class b_sort {
public:
	void bubble_sort(T arr[], int sz) {
		for (int i = 0; i < sz - 1; i++) {
			for (int j = 0; j < sz - i - 1; j++) {

				if (arr[j] > arr[j + 1]) {
					T tmp = arr[j];
					arr[j] = arr[j + 1];
					arr[j + 1] = tmp;
				}
			}
		}
	}

};


int main()
{
	//实例化一个对象
	//排序整型
	b_sort<int> sort;
	int arr[] = { 8,3,1,5,63,2,7,9};
	int sz = sizeof(arr) / sizeof(arr[0]);
	sort.bubble_sort(arr,sz);
	for (int i = 0; i < sz;i++) {
		cout << arr[i] << " ";
	}

	cout << endl;
	cout << endl;


	//实例化一个对象
	//排序字符型
	b_sort<char> sort2;
	char arr2[] = {'f','r','w','h','b','a'};
	int sz2 = sizeof(arr2) / sizeof(arr2[0]);
	sort2.bubble_sort(arr2, sz2);
	for (int i = 0; i < sz2; i++) {
		cout << arr2[i] << " ";
	}

	cout << endl;
	cout << endl;

	//实例化一个对象
	//排序自定义类型
	b_sort<People> sort3;
	People people1('l');
	People people2('z');
	People people3('l');
	People people4('i');
	People arr3[] = {people1,people2,people3,people4 };
	int sz3 = sizeof(arr3) / sizeof(arr3[0]);
	sort3.bubble_sort(arr3, sz3);
	for (int i = 0; i < sz3; i++) {
		cout << arr3[i].str << " ";
	}

	return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Bean如何诞生与消亡:生命周期探秘【beans 二】

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 Bean如何诞生与消亡&#xff1a;生命周期探秘【beans 二】 前言bean的创建过程bean的初始化阶段1. 实现InitializingBean接口&#xff1a;2. 使用PostConstruct注解&#xff1a; bean的属性注入1. Set…

视频倒放软件,看视频如何演绎“逆袭”之旅

你是否厌倦了日复一日的平淡生活&#xff0c;渴望时光倒流&#xff0c;重温那些逝去的精彩瞬间&#xff1f;在数字技术的世界里&#xff0c;这样的愿望或许不再遥不可及。视频倒放仿佛让时光倒流&#xff0c;给我们的视觉带来了全新的冲击&#xff0c;今天&#xff0c;让我们一…

新手第一次在linux上用git上传代码到仓库全过程

目录 背景&#xff1a; 过程&#xff1a; -1.去github.com自己的账号先建个仓库repository 0.命令行输入 git version 看下有无安装git 1.git init 初始化了一个Git仓库&#xff0c;你可以 ls -a 看见这个隐藏的目录 3.git add . 添加要上传的文件到Git的暂存区&#xff0…

windows对微信及小程序抓包:Burp+Fiddler+Proxifier

本文由掌控安全学院 - zbs 投稿 话不多说&#xff0c;直接先上个效果图&#xff1a; 新新的版本哈&#xff1b; 好好的抓包哈&#xff1b; 然后直接说我如何配置的&#xff1a; 准备好三个工具&#xff1a;bp、fiddler、proxifier【也可以用其他的进行代理】 bp、proxifie…

ELement UI时间控件el-date-picker误差8小时解决办法

一、问题描述&#xff1a; 在项目中引用了elementui中的date-picker组件&#xff0c;选中的时间跟实际相差八小时&#xff0c;且格式不是自己想要的格式 <el-date-pickertype"date"placeholder"选择日期"format"yyyy/M/d"v-model"form…

R304S 指纹识别模块的硬件接口说明

一.外部接口尺寸图 二.串行通讯 R304S 指纹模块通讯接口定义&#xff1a; 引脚号名称定义描述15V电源输入电源正输入端 DC 4.2--6V2GND电源和信号地电源和信号地3TXD数据发送串行数据输出&#xff0c;TTL 逻辑电平4RXD数据接收串行数据输入&#xff0c;TTL 逻辑电平 三.USB通…

EtherCAT的COE报文

本文主要用于记录工作中需要学习的内容&#xff0c;如有冒犯请私信&#xff01; COE协议 下面我们介绍以下CANOpen在EtherCAT中的应用。 COE的对象字典 COE协议是完全遵循CANopen协议的&#xff0c;但针对EtherCAT通信做了一些扩展&#xff0c;索引为0x1c00~0x1c4f&#xff0…

Java中关键词strictfp有什么作用?

在Java中&#xff0c;关键词strictfp用于声明一个方法、类或接口是严格遵守浮点数计算规范的。 具体作用包括&#xff1a; 保证浮点数计算的结果在不同平台上是一致的&#xff0c;避免由于浮点数计算的不精确性导致的结果不确定性。 指定了严格的浮点数计算规则&#xff0c;禁…

LeetCode刷题---矩阵置零

解题思路&#xff1a; 本题要求原地置换元素 对矩阵进行第一轮遍历&#xff0c;使用第一行第一列来充当该行该列是否要置换为0的标记位&#xff0c;如果第一行或第一列本身就含有零元素&#xff0c;我们使用colZero和rowZero变量来对其标记。如果第i行第j列的那个元素为0&#…

产品经理如何选择城市?

年底&#xff0c;全国性的人口大迁徙即将开始。选择城市&#xff0c;堪称年轻人的“二次投胎”&#xff0c;族望留原籍&#xff0c;家贫走他乡。 古人在选择城市时&#xff0c;主要的考量因素是家族势力&#xff0c;这一点放在当代&#xff0c;大致也成立&#xff0c;如果在老…

Cell 文章图复现

多组差异火山图复现 参考文章: A Spatiotemporal Organ-Wide Gene Expression and Cell Atlas of the Developing Human Heart Figure 2. H 图里主要是单细胞数据不同cluster之间的差异火山图, 所以说白了就是散点图和柱状图的结合, 散点图用差异基因绘制, 柱状图利用logFC最…

关于MIPS上手应知应会-如何把C语言改写为MIPS!

文章目录 寄存器指令使用技巧翻译C/Cif/else语句switch语句for循环while 循环do...while循环一维数组定义与使用二维数组定义与使用例 &#xff1a;哈密顿回路 注意立即数被符号位扩展 参考链接 寄存器 NameReg. NumUsage z e r o zero zero0constant value 0(恒为0) a t at a…

TypeScript Array(数组)

目录 1、数组初始化 2、Array 对象 3、数组迭代 4、数组在函数中的使用 4.1、作为参数传递给函数 4.2、作为函数的返回值 5、数组方法 数组对象是使用单独的变量名来存储一系列的值。数组非常常用。假如你有一组数据&#xff08;例如&#xff1a;网站名字&#xff09;…

Java中的IO与NIO篇----第三篇

系列文章目录 文章目录 系列文章目录前言一、信号驱动 IO 模型二、异步 IO 模型三、JAVA NIO四、NIO 的缓冲区前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。 一、…

P1423 小玉在游泳python

s float(input()) sum 0 step 0 meter 2.0 while sum < s:sum metermeter 0.98 * meterstep 1 print(step)

三、C语言中的分支与循环—switch语句(4)分支结构 完

本章分支结构的学习内容如下&#xff1a; 三、C语言中的分支与循环—if语句 (1) 三、C语言中的分支与循环—关系操作符 (2) 三、C语言中的分支与循环—条件操作符 与逻辑操作符(3) 三、C语言中的分支与循环—switch语句&#xff08;4&#xff09;分支结构 完 本章循环结构的…

linux创建pyspark虚拟环境

一、创建虚拟环境 conda create -n test python3.6.6 二、注意添加镜像 vi /root/.condarc channels:- http://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/- http://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/- http://mirrors.ustc.edu.cn/anaconda/pkgs/ma…

jmeter使用心得(一)

jmeter作为接口测试的常用工具之一&#xff0c;在我们的测试中经常会用到&#xff0c;往期的文章中&#xff0c;我们也分享过jmeter的各种功能和用法&#xff0c;基本覆盖了方方面面&#xff0c;可以满足各种接口测试的需求。但实际测试中我们也会发现&#xff0c;jmeter这么强…

测试管理-缺陷管理工具安装

前言&#xff1a; 项目生命周期里面&#xff0c;开发软件后&#xff0c;需要进行正规的测试&#xff0c;测试除了需要编写测试用例和写测试总结外&#xff0c;还需要进行bug的闭环控制&#xff0c;方便追踪。之前用过惠普的QC系统&#xff0c;这个是收费的&#xff0c;专业做缺…

【网络】网络层IP地址和IP数据报的格式

&#x1f984; 个人主页——&#x1f390;开着拖拉机回家_Linux,大数据运维-CSDN博客 &#x1f390;✨&#x1f341; &#x1fa81;&#x1f341;&#x1fa81;&#x1f341;&#x1fa81;&#x1f341;&#x1fa81;&#x1f341; &#x1fa81;&#x1f341;&#x1fa81;&am…