基于 多态 的职工管理系统(Staff Management System)

news2024/9/21 2:47:53

目录

一、管理系统需求

作用:管理公司内所有员工的信息

分类:要显示每位员工的编号、姓名、岗位与职责

具体实现的功能:

二、创建管理 类

三、各个接口函数

1、菜单展示功能

2、 选择功能

3、创建员工功能

        ①普通员工employee

        ②经理manager

        ③老板boss

4、添加功能

        4.1 添加员工

        4.2将添加的员工保存到文件中

         4.2.1写文件

         4.2.2读文件

5、显示员工

6、删除员工

6、修改员工

7、查找员工

8、排序员工

9、清空文件


一、管理系统需求

作用:管理公司内所有员工的信息


分类:要显示每位员工的编号、姓名、岗位与职责

普通员工:完成经理交给的任务

经理:完成老板交给的任务,并下发给员工

老板:管理公司所有事务


具体实现的功能:

①添加:实现批量添加职工功能,将职工信息(编号、姓名、职位)录入到文件中

②显示:显示当前公司内所有员工的信息

③删除:按照编号删除指定的员工

④修改:按照编号修改指定员工的信息

⑤查找:按照员工的姓名或编号

查找员工并显示其信息

⑥排序:按照员工编号进行升序或降序排列

⑦清空:清空文件中所有员工信息(需二次确认)

⑧退出:退出当前管理系统


二、创建管理 类

管理 类的作用:

①供用户选择的菜单界面

②对员工增删查改等的操作

③与数据文件的读写交互


首先需要头文件与源文件

并在文件中写入管理 类,并加上空的构造/析构函数

#pragma once
#include<iostream>
using namespace std;

class WorkerManager
{
public:
	// 构造函数
	WorkerManager();
	// 析构函数
	~WorkerManager();
};

并在源文件中空实现

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

	// 构造函数
WorkerManager::WorkerManager()
{

}
// 析构函数
WorkerManager::~WorkerManager()
{

}

三、各个接口函数

1、菜单展示功能

先在头文件的类中声明函数

	void Show_Menu();

 再在源文件中实现

void WorkerManager:: Show_Menu()
{
	cout << "***************************************" << endl;
	cout << "******** 欢迎使用教工管理系统!********" << endl;
	cout << "************ 1、添加员工 **************" << endl;
	cout << "************ 2、删除员工 **************" << endl;
	cout << "************ 3、显示员工 **************" << endl;
	cout << "************ 4、修改员工 **************" << endl;
	cout << "************ 5、查找员工 **************" << endl;
	cout << "************ 6、排序员工 **************" << endl;
	cout << "************ 7、清空员工 **************" << endl;
	cout << "************ 8、退出系统 **************" << endl;
	cout << "***************************************" << endl;
}

接下来我们回到主函数的源文件创建系统并尝试菜单功能

int main()
{
	WorkerManager WM;
	WM.Show_Menu();

	return 0;
}


2、 选择功能

在主函数中我们使用switch语句使得系统实现选择功能,并加上退出功能

int main()
{
	WorkerManager WM;
	int choice = 0;
	while (true)
	{
		WM.Show_Menu();
		cout << "请选择" << endl;
		cin >> choice;
		switch (choice)
		{
			case 1: // 添加
				break;
			case 2: // 删除
				break;
			case 3: // 显示
				break;
			case 4: // 修改
				break;
			case 5: // 查找
				break;
			case 6: // 排序
				break;
			case 7: // 清空
				break;
			case 0: // 退出
				WM.Exit_System();
				break;
			default:
				system("cls");
				break;
		}
	}
	return 0;
}
void WorkerManager:: Exit_System()
{
	cout << "退出系统!" << endl;
	exit(0);
}

3、创建员工功能

首先创建worker.h头文件,其内创建职工Worker基类,包含员工编号、姓名与岗位编号

// 员工抽象类_基类

class Worker
{
public:
	// 展示个人信息
	virtual void showInfo() = 0;
	// 获取个人岗位
	virtual string getDeptName() = 0;

	int m_id;		// 员工编号
	string m_name;// 员工姓名
	int m_Did;	// 所属部门编号
};

不需要具体实现,接下来,实现普通员工:

①普通员工employee

创建员工头文件employee.h源文件employee.cpp,并包含worker.h

头文件:子类employee继承父类Worker

class employee :public Worker
{
public:
	// 构造函数
	employee(int id, string name, int Did);
	// 展示个人信息
	virtual void showInfo();
	// 获取个人岗位
	virtual string getDeptName();
};

源文件:

    // 构造函数
employee::employee(int id, string name, int Did)
{
	this->m_id = id;
	this->m_name = name;
	this->m_Did = Did;
}
	// 展示个人信息
void employee:: showInfo()
{
	cout << "员工编号:" << this->m_id
		<< "\t员工姓名:" << this->m_name
		<< "\t员工岗位:" << this->getDeptName()
		<< "\t员工职责:完成经理安排的任务" << endl;
}
	// 获取个人岗位
string employee::getDeptName()
{
	return "普通员工";
}

main中测试:(先包含头文件和源文件)

int main()
{
	// test:

	Worker* worker = NULL;
	worker = new employee(22,"Joyce",1); 
	worker->showInfo();
	
	return 0;
}


②经理manager

同理:创建子类manager类,并继承父类Worker

头文件:

// 经理—子类
class manager :public Worker
{
public:
	// 构造函数
	manager(int id, string name, int Did);
	// 展示个人信息
	virtual void showInfo();
	// 获取个人岗位
	virtual string getDeptName();
};

源文件:

    // 构造函数
manager::manager(int id, string name, int Did)
{
	this->m_id = id;
	this->m_name = name;
	this->m_Did = Did;
}
	// 展示个人信息
void manager::showInfo()
{
	cout << "员工编号:" << this->m_id
		<< "\t员工姓名:" << this->m_name
		<< "\t员工岗位:" << this->getDeptName()
		<< "\t员工职责:完成老板安排的任务" << endl;
}
	// 获取个人岗位
string manager::getDeptName()
{
	return "经理";
}

③老板boss

同理:创建子类boss类,并继承父类Worker

头文件:

// 老板—子类
class boss :public Worker
{
public:
	// 构造函数
	boss(int id, string name, int Did);
	// 展示个人信息
	virtual void showInfo();
	// 获取个人岗位
	virtual string getDeptName();
};

源文件:

	// 构造函数
boss::boss(int id, string name, int Did)
{
	this->m_id = id;
	this->m_name = name;
	this->m_Did = Did;
}
	// 展示个人信息
void boss::showInfo()
{
	cout << "员工编号:" << this->m_id
		<< "\t员工姓名:" << this->m_name
		<< "\t员工岗位:" << this->getDeptName()
		<< "\t员工职责:安排所有任务" << endl;
}
	// 获取个人岗位
string boss::getDeptName()
{
	return "老板";
}

创建测试案例:(记得包含各个职位头文件)

int main()
{
	// test:
	Worker* worker1 = NULL;
	worker1 = new employee(1,"Joyce",1); 
	worker1->showInfo();
	delete worker1;

	Worker* worker2 = NULL;
	worker2 = new manager(2, "Nana", 2);
	worker2->showInfo();
	delete worker2;

	Worker* worker3 = NULL;
	worker3 = new boss(3, "Baby",3);
	worker3->showInfo();
	delete worker3;
	return 0;
}


4、添加功能

作用:批量添加员工,并保存到文件中


4.1 添加员工

首先,用户在添加员工时,会有不同的职位,如果我们把所有种类员工信息直接塞进一个数组中,存储将会困难,也可能会占用大量内存

因此,我们创建一个员工接着就创建一个指针,使该指针指向该员工的信息数据,并保存指针到一个数组中,这样我们在数组中就只有指针

而且,想要在程序中维护这个不定长度的指针,我们将数组创建到堆区,并使用Worker**的指针维护


代码:

首先在workerManager文件WorkerManager类中添加记录员工数量储存员工信息的指针这两个属性,并加入Add添加员工的接口函数

	// 记录员工数量
	int worker_num;

	// 储存员工的数组
	Worker** worker_array;

	// 添加员工功能
	void Add();

接着在workerManager的文件中的构造函数中初始化这两个属性

// 构造函数
WorkerManager::WorkerManager()
{
	// 初始化属性
	this->worker_num = 0;
	this->worker_array = NULL;
}

实现Add添加员工函数 

void WorkerManager::Add()
{
	cout << "请输入要添加员工的个数:"<< endl;
	int Add_num = 0;
	cin >> Add_num;
	if (Add_num > 0)
	{
		// 计算添加后员工的总数
		int newSize = this->worker_num + Add_num;
		
		// 开辟新空间
		Worker** newSpace = new Worker * [newSize];

		// 将原来空间的数据拷贝到新空间
		if (this->worker_array != NULL)
		{
			for (int i = 0; i < this->worker_num; i++)
			{
				newSpace[i] = this->worker_array[i];
			}
		}
		// 将新数据添加至新空间的后面
		for (int j = 0; j < Add_num; j++)
		{
			int id;
			string name;
			int Did;
			cout << "请输入第" << j + 1 << "个新员工的编号" << endl;
			while (true)
			{
				cin >> id;
				int ret = this->worker_isExit(id);
				if (ret != -1)
				{
					cout << "用户编号已存在!请重新输入:" << endl;
				}
				else
				{
					break;
				}
			}
			cout << "请输入第" << j + 1 << "个新员工的姓名" << endl;
			cin >> name;
			cout << "请输入第" << j + 1 << "个新员工的部门:" << 
				"1、普通员工 "
				"2、经理 "
				"3、老板"<<endl;
			cin >> Did;

			// 根据部门编号创建不同的职位
			Worker* worker = NULL;
			switch (Did)
			{
				case 1:
					worker = new employee(id, name, Did);
					break;
				case 2:
					worker = new manager(id, name, Did);
					break;
				case 3:
					worker = new boss(id, name, Did);
					break;
				default:
					cout << "输入错误" << endl;
					break;
			}
			// 将创建的员工指针,保存至数组中
			newSpace[this->worker_num + j] = worker;
		}
		// 释放原有数组的空间
		delete[] this->worker_array;
		// 更新新空间的指向
		this->worker_array = newSpace;
		// 更新新空间的人数
		this->worker_num = newSize;
		cout << "成功添加" << Add_num << "名新员工!" << endl;
		Sleep(1000); // 暂停1000毫秒
		system("pause");// 按任意键继续
		system("cls"); // 清屏
	}
	else
	{
		cout << "输入错误!" << endl;
	}
}

然后,记得堆区手动开辟的数据要手动释放,析构函数

// 析构函数
WorkerManager::~WorkerManager()
{
	if (this->worker_array != NULL)
	{
		delete[]this->worker_array;
		this->worker_array = NULL;
	}
}

最后在main函数加入Add函数后进行测试


4.2将添加的员工保存到文件中

添加头文件<fstream>后就可以直接开始


 4.2.1写文件

首先在主体函数中添加保存数据到文件的save函数

然后在源文件中实现:

void WorkerManager::save()
{
	ofstream	ofs;
	ofs.open("WorkerFile.txt", ios::out);
	for (int i = 0; i < this->worker_num; i++)
	{
		ofs << this->worker_array[i]->m_id<<" "
			<< this->worker_array[i]->m_name << " "
			<< this->worker_array[i]->m_Did << endl;
	}
	ofs.close();
}

最后在Add函数中调用即可


 4.2.2读文件

作用:将文件中的内容读取到程序中

上面实现了将添加的员工保存到文件中,但是文件中的员工信息我们还不能读取到程序中


而文件实际有3种状态:

①第一次使用程序,文件未创建不存在

②文件存在,但数据被用户清空

③文件存在,保存有员工的数据


我们在workerManager头文件中添加新的变量:bool m_FileIsEmpty;来判断文件是否为空

 然后修改源文件中构造函数

①文件不存在

// 构造函数
WorkerManager::WorkerManager()
{
	// 1、文件不存在
	ifstream ifs;
	ifs.open("FILENAME", ios::in);

	if (!ifs.is_open())
	{
		cout << "文件不存在!" << endl;
			// 初始化属性
		this->worker_num = 0;
		this->worker_array = NULL;
		this->m_FileIsEmpty = true;// 初始为空
	}
}

②文件存在,但无数据

我们将文件取1个字符到一个字符变量里,然后使用函数eof()判断文件是否为空,若函数为真则为空(若无数据,文件里最后一个字符将是EOF文件结束标志,上面提取了就没了为空)

	// 2、文件存在,无数据
	char ch = 0;
	ifs >> ch; // 取1个字符
	if (ifs.eof())
	{
		cout << "文件为空!" << endl;
			// 初始化属性
		this->worker_num = 0;
		this->worker_array = NULL;
		this->m_FileIsEmpty = true;// 初始为空
		ifs.close();
	}

③文件存在有数据

首先我们增加一个统计文件中有多少人函数get_WorkerNum()

 在源文件中实现

int WorkerManager::get_WorkerNum()
{
	ifstream ifs;
	ifs.open(FILENAME, ios::in);
	int id;
	string name;
	int Did;
	int number = 0;
	while (ifs >> id && ifs >> name && ifs >> Did)// 读取一行
	{
		number++;
	}
	return number;
}

 然后实现一个初始化员工的函数Init()

void WorkerManager::Init()
{
	ifstream ifs;
	ifs.open(FILENAME, ios::in);
	int id;
	string name;
	int Did;
	int number = 0;

	while (ifs >> id && ifs >> name && ifs >> Did)
	{
		Worker* worker = NULL;
		// 根据不同的部门创建不同的对象
		if (Did == 1)
		{
			worker = new employee(id,name,Did);
		}
		else if (Did == 2)
		{
			worker = new manager(id, name, Did);
		}
		else
		{
			worker = new boss(id, name, Did);
		}
		this->worker_array[number] = worker;// 将对象放在数组中维护
		number++;
	}
	ifs.close();
}

最后补全③

首先获取员工的个数,然后根据个数创建空间,然后初始化空间

	// 3、文件存在,有数据
	// 先获取员工的个数
	int num = get_WorkerNum();
	cout << "共有" << num << "个员工" << endl;
	this->worker_num = num;

	// 根据个数创建空间
	this->worker_array = new Worker * [this->worker_num];
	// 初始化员工
	this->Init();

加上测试

// 测试:
	for (int i=0; i < this->worker_num; i++)
	{
		cout << "员工编号:" << this->worker_array[i]->m_id <<
			"\t员工名字:" << this->worker_array[i]->m_name <<
			"\t部门为" << this->worker_array[i]->m_Did << endl;
	}

 5、显示员工

直接调用showInfo()函数即可


分为3种情况:

①文件为空,没有员工②文件存在,没有员工③文件存在,有员工

①和②可以合并


首先在workerManager头文件中创建show_worker()函数

然后在源文件中实现

void WorkerManager::show_worker()
{
	if (this->m_FileIsEmpty)
	{
		cout << "文件为空或不存在!" << endl;
		Sleep(1000);
	}
	else
	{
		for (int i = 0; i < this->get_WorkerNum(); i++)
		{
			this->worker_array[i]->showInfo();
			Sleep(50); 
		}
	}	
		system("pause");// 按任意键继续
		system("cls"); // 清屏
}

6、删除员工

分为3步,首先判断员工是否存在,存在返回员工编号,然后删除员工编号的数据


首先创建判断员工是否存在worker_isExit()函数删除员工函数del_worker()

先实现worker_isExit()函数

int WorkerManager::worker_isExit(int id)
{
	for (int i = 0; i < this->worker_num; i++)
	{
		if (this->worker_array[i]->m_id == id)
			return i;
	}
	return -1;
}

然后实现del_worker()函数:从要删除的数据开始从后往前覆盖数据即可

void WorkerManager::del_worker()
{
	if (this->m_FileIsEmpty)
	{
		cout << "文件为空!" << endl;
	}
	else
	{
		cout << "请输入要删除的员工id:" << endl;
		int input = 0;
		cin >> input;
		int ret = worker_isExit(input);
		if (ret == -1)
		{
			cout << "删除失败,员工不存在!" << endl;
		}
		else
		{
			if (input == this->worker_num) // 如果输入的是末尾员工的id,数组直接 - 1即可
			{
				this->worker_num--;
			}
			else
			{
                   // 数据前移,数组中后一个数据覆盖到前一个
				for (int i = ret; i < this->worker_num - 1; i++)
				{
					this->worker_array[i] = this->worker_array[i + 1];
				}
				this->worker_num--;
			}
			this->save();
			cout << "删除成功!" << endl;
		}
	}
	Sleep(1000);
	system("pause");// 按任意键继续
	system("cls"); // 清屏
}

6、修改员工

worker_Manager头文件创建修改员工函数mod_worker();


输入要修改的员工编号,存在则先delete掉那个位置的员工数据,然后重新new一个worker,再写入其编号姓名与部门,最后把worker赋值给刚才delete掉的那个位置

void WorkerManager::mod_worker()
{
	if (this->m_FileIsEmpty)
	{
		cout << "文件不存在或为空!" << endl;
	}
	else
	{
		cout << "请输入要修改的员工id:" << endl;
		int input = 0;
		cin >> input;
		int ret = worker_isExit(input);
		if (ret == -1)
		{
			cout << "修改失败,员工不存在!" << endl;
		}
		else
		{
			delete this->worker_array[ret];
			int id = 1;
			string name;
			int Did;
			cout << "已查找到,请输入员工新的编号" << endl;
			while (true)
			{
				cin >> id;
				int ret = this->worker_isExit(id);
				if (ret != -1)
				{
					cout << "用户编号已存在!请重新输入:" << endl;
				}
				else
				{
					break;
				}
			}
			cout << "请输入员工新的姓名" << endl;
			cin >> name;
			cout << "请输入员工新的部门:" <<
				"1、普通员工 "
				"2、经理 "
				"3、老板" << endl;
			cin >> Did;

			// 根据部门编号创建不同的职位
			Worker* worker = NULL;
			switch (Did)
			{
				case 1:
					worker = new employee(id, name, Did);
					break;
				case 2:
					worker = new manager(id, name, Did);
					break;
				case 3:
					worker = new boss(id, name, Did);
					break;
				default:
					cout << "输入错误" << endl;
					break;
			}
			this->worker_array[ret] = worker;
			cout << "修改成功!" << endl;
			this->save();
		}
	}
	Sleep(1000);
	system("pause");
	system("cls");
}

7、查找员工

有2种方式:①编号查找②姓名查找

也就是分别对比编号姓名是否相等即可


首先创建查找员工函数find_worker();

 然后在源文件中实现:

        比对信息很简单,只要将输入的内容遍历与文件中的信息对比即可,有则输出信息,没有则输出查无此人。

        同时,我们创建是否找到员工变量woreker_isFind;初始值即为false,找到员工改为true,遍历完后再根据true或者false确定是否输出查无此人。

void WorkerManager::find_worker()
{
	cout << "请输入查找模式:" << endl;
	cout << "1、编号查找	2、姓名查找	" << endl;
	int input = 0;
	cin >> input;
	// 1、编号查找
	if (input == 1)
	{
		cout << "请输入要查找人的编号:" << endl;
		int id = 0;
		cin >> id;
		int ret = this->worker_isExit(id);
		if (ret == -1)
		{
			cout << "查无此人!" << endl;
		}
		else
		{
			cout << "已查到编号为 " << id << " 的员工,信息如下:" << endl;
			this->worker_array[ret]->showInfo();
		}
	}
	// 2、姓名查找
	else if (input == 2)	
	{
		cout << "请输入要查找人的姓名:" << endl;
		string name;
		// 创建是否找到员工的变量,找到返回true,否则一直是false
		bool worker_isFind = false;
		cin >> name;
		for (int i = 0; i < this->worker_num; i++)
		{
			if (name == this->worker_array[i]->m_name)
			{
				cout << "已查到姓名为 " << name << " 的员工,信息如下:" << endl;
				this->worker_array[i]->showInfo();
				worker_isFind = true;
			}
		}
		if (worker_isFind == false)// 根据是否找到员工(即是否是false),输出查无此人
		{
			cout << "查无此人!" << endl;
		}
	}
	else
	{
		cout << "输入错误!" << endl;
		return;
	}
	Sleep(1000);
	system("pause");
	system("cls");
}

8、排序员工

2种方法:升序排列or降序排列

我们使用选择排序

void WorkerManager::sort_worker()
{
	if (this->m_FileIsEmpty)
	{
		cout << "文件不存在或为空!" << endl;
		system("pause");
		system("cls");
	}
	else
	{
		cout << "请输入排序方式:" << endl;
		cout << "1、升序排序    2、降序排序 " << endl;
		int input = 0;
		cin >> input;
		int minORmax = 0;

		for (int i = 0; i < this->worker_num; i++)
		{
			int minORmax = i; // 设定最小值或最大值
			for (int j = i + 1; j < this->worker_num; j++)
			{
				if (input == 1) // 升序
				{
					if (this->worker_array[minORmax]->m_id > this->worker_array[j]->m_id)
					{	// 如果我们设定的最小值比数组中某个数还小
						minORmax = j; //交换下标
					}
				}
				else // 降序
				{
					if (this->worker_array[minORmax]->m_id < this->worker_array[j]->m_id)
					{	// 如果我们设定的最小值比数组中某个数还大
						minORmax = j;
					}
				}
			}
			if (i != minORmax) // 下标有交换,则和原来的i不同,就可以进行数据的交换
			{
				swap(this->worker_array[minORmax], this->worker_array[i]);
			}
		}
		this->save();
		cout << "排序成功!" << endl;
		cout << "排序后结果为:" << endl;
		this->show_worker();
	}
}

9、清空文件

先创建销毁函数

源文件中实现:

清空文件,再销毁数组

销毁数组时,先销毁每个元素,再销毁整个数组。

void WorkerManager::cleam_worker()
{

	if (this->m_FileIsEmpty)
	{
		cout << "文件不存在或为空!" << endl;
		system("pause");
		system("cls");
	}
	else
	{
		cout << "确认清空文件?" << endl;
		cout << "1、确定   2、返回" << endl;
		int input = 0;
		cin >> input;
		if (input == 1)
		{
			// 1、先清空文件
			// 直接使用文件打开方式的 trunc:文件存在先删除再创建
			ofstream ofs(FILENAME, ios::trunc);
			ofs.close();

			// 2、再清空数组
			if (this->worker_array != NULL)
			{
				// 2.1先删除堆区每个员工对象(数组每个元素)
				for (int i = 0; i < this->worker_num; i++)
				{
					delete this->worker_array[i];
					this->worker_array[i] = NULL;
				}
			}
			// 2.2再清空数组
			delete[]this->worker_array;
			this->worker_array = NULL;
			this->worker_num = 0;
			this->m_FileIsEmpty = true; // 文件为空的标志
		}
		cout << "清空成功!" << endl;
		system("pause");
		system("cls");
	}
}

至此完成全部功能。

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

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

相关文章

【Web3.0大势所趋】我看到了互联网未来的模样

前言 Web3.0 是一个越来越受到关注的话题&#xff0c;它被认为将会带来天翻地覆的变化。本文我们一起来谈谈 Web3.0 的概念、特点和优势&#xff0c;并探讨它为什么如此重要和具有革命性的。 文章目录 前言Web3.0是什么Web3.0的技术Web3.0的优势总结 Web3.0是什么 Web3.0: 是下…

尚硅谷Kafka

Kafka 1.Kafka概述1.1 定义1.2 消息队列1.2.1 传统消息队列的应用场景1.2.2 消息队列的两种模式 1.3 kafka基础架构 2.快速入门2.1 kafka环境安装2.2 kafka命令行操作参数2.2.1 主题命令行操作 2.2.2 生产者命令行操作2.2.3 消费者命令行操作 3.Kafka 生产者3.1 生产者消息发送…

Vue3+Vite神器:按需引入自定义组件unplugin-vue-components

前言 我们做项目时&#xff0c;会封装大量的公共组件&#xff0c;如果我们每一个都去在maints里面引入&#xff0c;非常麻烦不说&#xff0c;代码也不优雅。所以更好的方法就是自动注册全局组件&#xff0c;在组件中直接使用就好。 一种方法是自己在components文件夹下新建in…

QML控件--MenuBar

文章目录 一、控件基本信息二、控件使用三、属性成员四、成员函数 一、控件基本信息 Import Statement&#xff1a;import QtQuick.Controls 1.4 Since&#xff1a;Qt 5.1 二、控件使用 MenuBar&#xff1a;是菜单栏&#xff0c;通常&#xff0c;菜单静态声明为菜单栏的子项&…

redis入门必会知识

Redis基础知识目录 5、sortedSet 文章目录 系列文章目录前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 前言 一、redis是什么&#xff1f; Redis&#xff08;Remote Dictionary Server )&#xff0c;即远程字典服务 ! 是一个开源的使用ANSI C语言编写…

【C++】——- 模板初阶介绍

前言&#xff1a; 在之前的学习中&#xff0c;我们已经把 C前期所需要用到的知识都给大家介绍了一遍。接下来&#xff0c;我们要学习的就是关于在C 中模板的基本知识&#xff0c;今天我带给大家的内容便是关于 模板初阶的介绍。 目录 &#xff08;一&#xff09; 泛型编程 &…

【Python_Opencv图像处理框架】图像形态学操作

写在前面 本篇文章是opencv学习的第三篇文章&#xff0c;主要讲解了图像的形态学有关操作&#xff0c;作为初学者&#xff0c;我尽己所能&#xff0c;但仍会存在疏漏的地方&#xff0c;希望各位看官不吝指正❤️ 写在中间 读完这篇文章后&#xff0c;相信您便能信手拈来下面图…

给照片换底色(python+opencv)

给照片换底色&#xff08;pythonopencv&#xff09; 本篇目录&#xff1a; &#x1f984; 一、分析照片基本信息 &#x1f984; 二、方法一&#xff08;遍历图像&#xff0c;将像素值点替换修改为指定颜色&#xff09; &#x1f984; 三、修改图片颜色方法二&#xff08;先转…

MySQL数据库索引

目录 0.知识回顾 1.数据库约束 一.索引 1.什么是索引 2.为什么要使用索引(作用) 3.索引的使用场景 4.如何使用索引 1.查看索引 2.创建索引 3.修改索引 4.删除索引 5.索引的分类 1.使用场景不同 2.按列区分 3.按数据组织方式 二.索引的数据结构 1.HASH 2.二叉搜…

如何设计自动化测试框架?阿里P7工程师耗时一个月总结而成

目录 一、什么是自动化测试框架 二、自动化测试框架的架构设计 三、自动化测试框架的最佳实践 四、自动化测试框架的组成部分 五、自动化测试框架的设计原则 六、如何选择自动化测试框架 七、自动化测试框架实例 八、结论 一、什么是自动化测试框架 自动化测试框架是一…

UE4/5多人游戏详解(八、游戏模式和游戏状态里的函数重写,插件内地图的地址做变量,做变量让按钮出现不同状态,插件内的所有代码)

目录 这里不写在插件里面&#xff0c;而是在游戏模式&#xff1a; 头文件&#xff1a; Cpp文件&#xff1a; 更改ini文件 进入地图设置模式&#xff1a; 写插件里面&#xff0c;做一个变量&#xff1a; 写变量 然后更改函数MenuSet&#xff1a; 在子系统中做变量&…

FPGA 20个例程篇:20.USB2.0/RS232/LAN控制并行DAC输出任意频率正弦波、梯形波、三角波、方波(四)

接着同样地我们也需要完成对千兆网口ETH模块和USB2.0模块的编写&#xff0c;实际上和UART串口模块的设计思想大同小异&#xff0c;也同样地需要完成两项关键功能即识别并解析报文、接收并发送数据&#xff0c;千兆网口ETH和USB2.0的底层驱动在前面的例程中也详细说明了&#xf…

常用的设计模式(单例模式、工厂模式等)

1.单例模式 概述: 在有些系统中&#xff0c;为了节省内存资源、保证数据内容的一致性&#xff0c;对某些类要求只能创建一个实例&#xff0c;这就是所谓的单例模式. 例如&#xff0c;Windows 中只能打开一个任务管理器&#xff0c;这样可以避免因打开多个任务管理器窗口而造…

Centos切换jdk版本

先安装了jdk1.8的版本&#xff0c;需要使用jdk17的版本 1.先安装jdk17&#xff0c;再配置环境变量&#xff1a; vim ~/.bashrc 2.在最后一行添加 ##这个添加的就是路径&#xff0c;一定要和自己jdk安装的路径是一致的 export JAVA_HOME/usr/lib/jvm/java-8-openjdk-amd64 3.然…

Mybatis框架超详解及运用总结

Mybatis 一、什么是Mybatils&#xff1f;二、第一个Mybatils程序2.1、创建springboot工程2.2、准备数据2.3、配置MyBatis2.4、编写SQL语句2.5、单元测试 三、JDBC四、数据库连接池五、lombok六、Mybatis基础操作6.1、删除6.2、新增6.2.1、主键返回 6.3、修改6.4、查询6.4.1、数…

【AI绘画】AI绘画的创意应用

目录 1.引言2.将AI生成的图像转化为数字艺术品2.1AI生成的画作拍卖2.2将AI生成的图像转化为雕塑 3.将AI生成的图像用于虚拟场景的创建3.1使用GAN生成虚拟人物3.2在虚拟场景中使用AI生成的图像 1.引言 当今的AI绘画技术已经发展到了让人惊艳的程度&#xff0c;不仅可以生成高质量…

【每日一题Day183】LC1187使数组严格递增 | dp

使数组严格递增【LC1187】 给你两个整数数组 arr1 和 arr2&#xff0c;返回使 arr1 严格递增所需要的最小「操作」数&#xff08;可能为 0&#xff09;。 每一步「操作」中&#xff0c;你可以分别从 arr1 和 arr2 中各选出一个索引&#xff0c;分别为 i 和 j&#xff0c;0 <…

缓存优化----SpringCache

spring cache spring Cache介绍 spring cache是一个框架&#xff0c;实现了基于注解的缓存功能&#xff0c;只需要简单地加一个注解&#xff0c;就能实现缓存功能。 Spring cache提供了一层抽象&#xff0c;底层可以切换不同的cache实现。具体就是通过CacheManager接口来统一不…

springboot JWT 搭建授权服务器

目录 0 基本介绍 0.1 课程视频 0.2 架构逻辑图 0.2.1 登录JWT与授权服务器交互 0.2.2 登录成功后JWT与gateway-server交互 路由限制 1 JWT私钥公钥 1.1 安装git ->win系统右键 -> git bash here 1.2 生成私钥jks文件 1.3 用私钥jks文件解析出公钥 1.4 保存 BEGI…

造型简约的机箱,安装简单兼容性好,安钛克P20C体验

我们准备组装一台新主机的时候&#xff0c;机箱确实很重要&#xff0c;它决定了主机的整体风格和兼容性。我比较喜欢用中塔机箱&#xff0c;像是上个月我新装的主机&#xff0c;用的就是安钛克P20C&#xff0c;这款机箱的设计很简约&#xff0c;而且还有多种版本可选&#xff0…