【C++】深度解析---赋值运算符重载(小白一看就懂!!)

目录

一、前言

二、 运算符重载

 🍎运算符重载

① 概念引入 

② 语法明细

③ 练习巩固

④ 代码展示

 🍇赋值运算符重载

① 语法说明及注意事项 

② 默认的赋值运算符重载 

③ 值运算符不能重载成全局函数!

三、总结

 四、共勉


一、前言

      【C++】为了增强代码的可读性引入了赋值运算符重载赋值运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。但是 赋值运算符重载 的应用细节很多和之前讲过的拷贝构造函数数有着千丝万缕的关系,所以本文就来详细的讲解一下赋值运算符重载。

二、 运算符重载

 🍎运算符重载

① 概念引入 

  • 之前呢我们都是对一个日期进行初始化、销毁等操作,现在若是我要去比较一下两个日期,该怎么实现呢?
class Date
{
public:
	
	// 构造函数
	Date(int year = 2024,int month = 4,int day = 14)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	//拷贝构造函数
	Date(Date& d)
	{
		cout << "调用拷贝构造" << endl;
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
	void Print()
	{
		std::cout << "year:" << _year << std::endl;
		std::cout << "month:" << _year << std::endl;
		std::cout << "day:" << _year << std::endl;
	}
	// 析构函数
	~Date()
	{
		cout << "调用析构构造" << endl;
		cout << endl;
		_year = 0;
		_month = 0;
		_day = 0;
	}

private:
	int _year;
	int _month;
	int _day;
};
int main()_
{
   Date d1(2024, 4, 14);
   Date d2(2024, 4, 14);
   cout<<(d1==d2)<<endl;
   return 0;
}
  • 可能你会想到直接这么去写,但是编译器允许吗?很明显它完全实现不了这样的比较

  • 于是就想到了把他们封装成为一个函数来进行实现
//等于==
bool Equal(const Date& d1, const Date& d2)
{
	//...
}

//小于<
bool Less(const Date& d1, const Date& d2)
{
	//...
}

//大于>
bool Greater(const Date& d1, const Date& d2)
{
	//...
}
Equal(d1, d2);
Less(d1, d2);
Greater(d1, d2);
  • 但是,你认为所有人都会像这样去仔细对函数进行命名吗,尤其是打一些算法竞赛的。它们可能就会把函数命名成下面这样

 若是每个函数都是上面这样的命名风格,那么调用的人该多心烦呀╮(╯▽╰)╭

  • 如果我们不用考虑函数名,可以直接用最直观的形式也就是一开始讲的那个样子去进行调用的话该多好呀

  • 但是呢编译器不认识我们上面所写的这种形式,之前我们去比较两个数的大小或者相等都是int、char、double这些【内置类型】的数据,对于这些类型是语法定义的,语言本身就已经存在了的,都将它们写进指令里了
  • 不过对于【自定义类型】而言,是我们自己定义的类型,编译器无法去进行识别,也无法去比较像两个日期这样的大小,所以对于自定义类型而言,在于以下两点
  1. 类型是你定义的,怎么比较,怎么用运算符应该由你来确定
  2. 自定义类型不一定可以加、减、乘、除,像两个日期相加是毫无意义的,相减的话还能算出他们之间所差天数【日期类中会实现日期加一个天数】

② 语法明细

基于上述的种种问题,C++为了增强代码的可读性引入了运算符重载 

 【概念】:运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似

【函数名字】:关键字operator后面接需要重载的运算符符号 

【函数原型】:返回值类型 operator 操作符(参数列表)

  • 根据上面的语法概念,就可以写出==的运算符重载函数
bool operator==(const Date& d1, const Date& d2)

 注意事项:

 接下去我便通过几点注意实现来带你进一步了解运算符重载

1️⃣:不能通过连接其他符号来创建新的操作符:比如operator@

2️⃣:重载操作符必须有一个类类型(自定义类型)参数

3️⃣:用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不能改变其含义

  • 可以看到,我重载了运算符+,内部实现了一个乘法运算,然后用当前对象的月数 * 10,最终改变了+运算符的含义,这种语法虽然是可以编译过的,但是写出来毫无意义,读者可以了解一下

 4️⃣:运算符重载可以放在全局,但是不能访问当前类的私有成员变量

  • 可以看到,虽然运算符重载我们写出来了,但是在内部调用当前对象的成员 时却报出了错误,说无法访问private的成员,那此时该怎么办呢?

👉解决办法1:去掉[private],把成员函数全部设置为公有[public] 

👉解决办法2:提供公有函数getYear()getMonth()getDay()

👉解决办法3:设置友元【不好,会破坏类的完整性】

👉解决办法4:直接把运算符重载放到类内

  • 此时我们来试试第四种解决方案,将这个函数放到类内。但是一编译却报出了下面这样的错误,这是为什么呢?【看看下一个点就知道了】

 5️⃣:作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this

  • 还记得我们在类和对象的的封装思想中学习过的类成员函数中都存在一个隐藏形参this,用于接收调用对象所传入的地址,上面我们在写【日期计算器】的是有也有在类内使用过这个this指针
  • 不过对于==来说是个【双目操作符】,其运算符只能有两个,那此时再加上隐藏形参this的话就会出现问题
bool operator==(Date* this, const Date& d1, const Date& d2)
  • 所以当运算符重载函数放到类内时,就要改变其形参个数,否则就会造成参数过多的现象,在形参部分给一个参数即可,比较的对象就是当前调用这个函数的对象即【this指针所指对象】与【形参中传入的对象】
bool operator==(const Date& d)
{
	return _year == d._year
		&& _month == d._month
		&& _day == d._day;
}
  • 那既然这是一个类内的函数,就可以使用对象.的形式去调用,运行结果如下

 6️⃣*、 ::、 sizeof ?: 、. 注意以上5个运算符不能重载。这个经常在笔试选择题中出现。

 7️⃣运算符重载和函数重载不要混淆了

【运算符重载】自定义类型对象可以使用运算符

【函数重载】支持函数名相同,参数不同的函数,同时可以用

 ③ 练习巩固

 上面教了要如何去写==的运算符重载,接下去我们就来对其他运算符写一个重载

  • 首先就是小于 ,读者可以试着自己在编译器中写写看
bool operator<(const Date& d) 
// 小于
bool operator<(const Date& d)
{
	if (_year < d._year) {
		return true;
	}
	else if (_year == d._year && _month < d._month) {
		return true;
	}
	else if (_year == d._year && _month == d._month && _day < d._day) {
		return true;
	}
	else {
		return false;
	}
}
  • 知道了==<如何去进行重载,那小于等于呢?该如何去实现?

有同学说:这简单,把 < 都改成 <= 不就好了 

bool operator<(const Date& d)
{
	if (_year <= d._year) {
		return true;
	}
	else if (_year == d._year && _month <= d._month) {
		return true;
	}
	else if (_year == d._year && _month == d._month && _day <= d._day) {
		return true;
	}
	else {
		return false;
	}
}
  • 确实上面这样是最直观的形式,但是刚才说了,我们在已经能够写对的情况下要去追求更优的情况。我采取的是下面这种写法,你能很快反应过来吗?
return (*this < d) || (*this == d);
  •  其实很简单,我就是做了一个【复用】,使用到了上面重载后的运算符 < ==this指向当前对象,那么*this指的就是当前对象,这样来看的话其实就一目了然了

小于、小于等于都会了,那大于>和大于等于>=呢?不等于!=呢? 

bool operator>(const Date& d)  
bool operator>=(const Date& d)  
bool operator!=(const Date& d)
  • 其实上面的这两个都可以用【复用】的思想去进行实现,相信此刻不用我说你应该都知道该如何去实现了把
//大于>
bool operator>(const Date& d)
{
	return !(*this <= d);
}

//大于等于>=
bool operator>=(const Date& d)
{
	return !(*this < d);
}

//不等于!=
bool operator!=(const Date& d)
{
	return !(*this == d);
}

这里就不给出测试结果了,读者可自己修改日期去查看一下 

④ 代码展示

class Date
{
public:
	
	// 构造函数
	Date(int year = 2024,int month = 4,int day = 14)
	{
		_year = 2024;
		_month = 4;
		_day = 14;
	}
	//拷贝构造函数
	Date(Date& d)
	{
		cout << "调用拷贝构造" << endl;
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
	void Print()
	{
		std::cout << "year:" << _year << std::endl;
		std::cout << "month:" << _year << std::endl;
		std::cout << "day:" << _year << std::endl;
	}
	// 析构函数
	~Date()
	{
		cout << "调用析构构造" << endl;
		cout << endl;
		_year = 0;
		_month = 0;
		_day = 0;
	}
	// 等于== 运算符重载
	bool operator==(const Date& d)
	{
		return _year == d._year
			&& _month == d._month
			&& _day == d._day;
	}
	// 小于< 
	bool operator<(const Date& d)
	{
		return _year < d._year
			|| (_year == d._year && _month < d._month)
			|| (_year == d._year && _month == d._month && _day < d._day);
	}
	// 小于等于 <=
	bool operator<=(const Date& d)
	{
		return (*this < d) || (*this == d);
	}
	// 大于>
	bool operator>(const Date& d)
	{
		return !(*this <= d);
	}
	// >=
	bool operator>=(const Date d)
	{
		return (*this < d);
	}

private:
	int _year;
	int _month;
	int _day;
};

 🍇赋值运算符重载

 有了运算符重载的概念后,我们就来讲讲什么是赋值运算符重载

① 语法说明及注意事项 

首先给出代码,然后我再一一分解叙述 

Date& operator=(const Date& d)
{
	if (this != &d)		//判断一下是否有给自己赋值
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
	return *this;
}

 👉 【参数类型】:const T&,传递引用可以提高传参效率

  • 这一点我在上面讲解拷贝构造的时候已经有重点提到过,加&是为了减少传值调用而引发的拷贝构造,加const则是为了防止当前对象被修改和权限访问的问题,如果忘记了可以再去看看这篇文章:拷贝构造函数

👉 【返回*this】 :要复合连续赋值的含义 

  • 这块重点讲一下,本来对于赋值运算符来说是不需要有返回值的,设想我们平常在定义一个变量的时候为其进行初始化使用的时候赋值运算,也不会去考虑到什么返回值,但是对于自定义类型来说,我们要去考虑这个返回值
Date d1(2023, 3, 27);
Date d2;
Date d3;

d3 = d2 = d1;
  • 可以看到,就是上面这种情况,当d1为d2进行初始化后,还要为d3去进行初始化,那此时就要使用到d2,所以我们在写赋值重载的时候要考虑到返回值的问题,那返回什么呢?
  •  因为是为当前对象做赋值,所以应该返回当前对象也就是*this 

 👉 【返回值类型】:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值

  • 返回值这一块我在引用一文也有相信介绍过,若是返回一个出了当前作用域不会销毁的变量,就可以使用引用返回来减少拷贝构造
  •  *this 是当前对象的引用,并不会在函数作用域结束时被销毁。*this 指的是调用成员函数的对象本身,即赋值运算符中 operator= 的左操作数。在赋值运算符函数结束后,*this 引用的对象依然存在,因为这个对象的生命周期与原来对象的生命周期一致。

👉 【多方位考虑】:检测是否自己给自己赋值 

  • 在外界调用这个赋值重载的时候,不免会有人写成下面这种形式
d1 = d1;
  • 那自己给自己赋值其实并没有什么意义,所以我们在内部应该去做一个判断,若是当前this指针所指向的地址和传入的地址一致的话,就不用做任何事,直接返回当前对象即可。若是不同的话才去执行一个赋值的逻辑
if (this != &d)

知晓了基本写法和注意事项后,我们就来测试运行一下看看是否真的可以完成自定义类型的赋值

  • 可以看到 ,确实可以使用=去进行日期之间的赋值

  • 不仅如此,也可以完成这种【链式】的连续赋值

  • 那现在我想问,下面的这两种都属于【赋值重载】吗?
  • 注意:d2 = d1就是我们刚才说的赋值重载,去类中调用了对应的成员函数;但是对于Date d3 = d2来说,却没有去调用赋值重载,而是去调用了【拷贝构造】,此时就会有同学很疑惑?

 这里一定要区分的一点是,赋值重载是两个已经初始化的对象才可以去做的工作;对于拷贝构造来说是拿一个已经实例化的对象去初始化另一个对象

② 默认的赋值运算符重载 

 重点地再来谈谈默认的赋值运算符重载,相信在看了构造、析构、拷贝构造后,本小节对你来说不是什么难事😎

  • 那还是咱熟悉的老朋友Time类和Date类,在Time类中我写了一个赋值重载
class Time
{
public:
	// 构造函数
	Time()
	{
		_hour = 1;
		_minute = 1;
		_second = 1;
	}
	// 赋值重载
	Time& operator=(const Time& t)
	{
		if (this != &t)
		{
			_hour = t._hour;
			_minute = t._minute;
			_second = t._second;
		}
		return *this;
	}
private:
	int _hour;
	int _minute;
	int _second;
};

class Date
{
public:
	Date(int y = 2000, int m = 1, int d = 1)
	{
		_year = y;
		_month = m;
		_day = d;
	}
private:
	// 基本类型(内置类型)
	int _year;
	int _month;
	int _day;
	// 自定义类型
	Time _t;
};
  • 我们首先通过如下结果进行观察

  • 可以发现,当使用d1初始化d2的时候,去调用了Time类的赋值运算符重载,这是为什么呢?我们其实可以先来看看Date类中的成员变量有:_year、_month、_day以及一个Time类的对象_t,通过上面的学习我们可以知道对于前三者来说都叫做【内置类型】,对于后者来说都叫做【自定义类型】
  •  那在构造、析构中我们有说到过对于【内置类型】编译器不会做处理;对于【自定义类型】会去调用默认的构造和析构。在拷贝构造中我们有说到过【内置类型】会按照值拷贝一个字节一个字节;对于【自定义类型】来说会去调用这个成员的拷贝构造
  • 那通过上面的调试可以看出赋值运算符重载似乎和拷贝构造是差不多,对于内置类型进行值拷贝,对于自定义类型Time去调用了其赋值重载函数 

 那我还是一样会提出疑问,既然编译器生成的默认赋值运算符重载函数已经可以完成字节序的值拷贝了,还需要自己实现吗?当然像日期类这样的类是没必要的。那么下面的类呢?验证一下试试?

  • 没错,也是我们的老朋友Stack类。我想你可能已经猜到了结果😆 
typedef int DataType;
class Stack
{
public:
	// 构造函数 
	Stack(size_t capacity = 10)
	{
		_array = (DataType*)malloc(sizeof(DataType) * capacity);
		if (nullptr == _array)
		{
			perror("malloc申请空间失败");
			return;
		}
		_capacity = capacity;
		_size = 0;
	}

	// 拷贝构造 
	Stack(const Stack& st)
	{
		//根据st的容量大小在堆区开辟出一块相同大小的空间
		_array = (DataType*)malloc(sizeof(DataType) * st._capacity);
		if (nullptr == _array)
		{
			perror("fail malloc");
			exit(-1);
		}

		memcpy(_array, st._array, sizeof(DataType) * st._size);		//将栈中的内容按字节一一拷贝过去
		_size = st._size;
		_capacity = st._capacity;
	}
	// // 赋值重载
	//Stack& operator=(const Stack& st)
	//{
	//	if (this != &st)
	//	{
	//		memcpy(_array, st._array, sizeof(DataType) * st._size);		//将栈中的内容按字节一一拷贝过去
	//		_size = st._size;
	//		_capacity = st._capacity;
	//	}
	//	return *this;
	//}
	void Push(const DataType& data)
	{
		// 扩容...
		_array[_size] = data;
		++_size;
	}

	DataType Top()
	{
		return _array[_size - 1];
	}
	// 析构函数
	~Stack()
	{
		if (_array)
		{
			free(_array);
			_array = nullptr;
			_capacity = 0;
			_size = 0;
		}
	}
private:
	DataType* _array;
	size_t _capacity;
	size_t _size;
};

int main()
{
	Stack s1;
	s1.Push(1);
	s1.Push(2);
	s1.Push(3);
	s1.Push(4);

	Stack s2;

	s2 = s1;
	return 0;
}
  • 不出所料,程序出现了奔溃,如果你认真看了上面内容的话,就能回忆起上面Stack在进行浅拷贝时出现的问题,和这里的报错是一模一样的

  •  我们知道,对于浅拷贝来说是就是一个字节一个字节直接拷贝,和拷贝构造不同的是,两个对象是已经实例化出来了的,_array都指向了一块独立的空间,但是在赋值之后,s1和s2的_array还是指向了同一块空间。此时便会造成两个问题
  • 因为它们是同一指向,所以在析构的时候就会造成二次析构
  • 原本s2中的_array所申请出来的空间没有释放会导致内存泄漏

 还是一个画个图来分析一下 

📚所以还是一样,当果类中未涉及到资源管理,赋值运算符是否实现都可以;一旦涉及到资源管理则必须要实现,所以遇到涉及到资源管理的类,就需要自行实现  赋值运算符重载

Stack& operator=(const Stack& st)
	{
		if (this != &st)
		{
			memcpy(_array, st._array, sizeof(DataType) * st._size);		//将栈中的内容按字节一一拷贝过去
			_size = st._size;
			_capacity = st._capacity;
		}
		return *this;
	}

 ③ 值运算符不能重载成全局函数!

  • 如下,可以看到我将赋值重载运算符放到了类外来定义,编译一下发现报出了错误,这是为什么呢?其实编译器已经给我们写得很明确了,对于operator=也就是赋值重载只能写在类内,不可以写在类外,但一定有同学还是会疑惑为什么要这样规定,且听我娓娓道来~

 拿一些权威性的东西来看看,以下是《C++ primer》中的原话

三、总结

 【总结一下】:

  • 本文我们介绍了两样东西,一个是运算符重载,一个是赋值运算符重载
  • 对于运算符重载来说,我们认识到了一个新的关键字operator,使用这个关键字再配合一些运算符封装成为一个函数,便可以实现对自定义类型的种种运算,也加深巩固了我们对前面所学知识的掌握
  • 对于赋值运算符重载而言,就是对赋值运算符=进行重载,分析了一些它的有关语法使用特性以及注意事项,也通过调试观察到了它原来和默认拷贝构造的调用机制是一样的,毕竟大家同为天选之子。但是也要区分二者的使用场景,不要混淆了

 四、共勉

  以下就是我对 赋值运算符重载 的理解,如果有不懂和发现问题的小伙伴,请在评论区说出来哦,同时我还会继续更新对C++ 的理解请持续关注我哦!!!  

 

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

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

相关文章

前端console用法分享

console对于前端人员来讲肯定都不陌生&#xff0c;相信大部分开发者都会使用console来进行调试&#xff0c;但它能做的绝不仅限于调试。 最常见的控制台方法 作为开发者&#xff0c;最常用的 console 方法如下&#xff1a; 控制台打印结果&#xff1a; 今天我分享的是一些 co…

Qt快速入门(MV架构之TableView + QStandardItemModel + 自定义代理小案例)

Qt快速入门&#xff08;MV架构之TableView QStandardItemModel 自定义代理小案例&#xff09; 关于MV架构的简单介绍 在Qt框架中&#xff0c;代理&#xff08;Delegate&#xff09;、模型&#xff08;Model&#xff09;和视图&#xff08;View&#xff09;之间的关系构成了…

jvisualVM分析jvm内存使用快照dump

服务发生内存溢出&#xff0c;就需要查看服务器上Java服务的jvm堆内存使用情况&#xff0c;可以使用dump命令生成dump文件&#xff0c;然后下载到本地&#xff0c;然后使用jvisualVM工具打开&#xff0c;即可实现可视化分析。 生成dump文件常用的两种方式&#xff1a; 第一种…

linux fixmap分析

本文基于Linux-4.19.125&#xff0c; ARM V7&#xff0c;dual core, MMU采用2级页表&#xff08;未开启LPAE&#xff09;。 1 为什么需要fixmap Linux内核启动过程中&#xff0c;经过汇编阶段后&#xff0c;mmu功能已经开启&#xff0c;后续只能通过虚拟地址来访问DDR&#x…

RAG应用开发实战02-相似性检索的关键 - Embedding

1 文本Embedding 将整个文本转化为实数向量的技术。 Embedding优点是可将离散的词语或句子转化为连续的向量&#xff0c;就可用数学方法来处理词语或句子&#xff0c;捕捉到文本的语义信息&#xff0c;文本和文本的关系信息。 ◉ 优质的Embedding通常会让语义相似的文本在空…

Linux 添加启动服务--Service

1&#xff0c;服务配置service文件 Service 服务的实际作用是开启后自动启动服务&#xff0c;运行一些不须要登录的程序&#xff0c;任务。 实例1、上电自动连接WIFI热点 1.1 新建.service文件 /etc/systemd/system/wificonnect.service [Unit] DescriptionService [wifico…

记录linux从0部署java项目(宝塔)

目录 一、安装宝塔可视化界面 二、部署前端 三、部署后端 1、配置并连接Mysql数据库 2、配置并连接redis 3、安装jdk 这里先记录一个安装后遇到的问题 安装openJDK 四、检查 一、安装宝塔可视化界面 宝塔面板下载&#xff0c;免费全能的服务器运维软件 运行安装脚本 安…

MySQL 社区版 安装总结

很早就安装过MySQL&#xff0c;没有遇到过什么问题&#xff0c;直接next就行了&#xff0c;这次在新电脑上安装却遇到了一些问题&#xff0c;记录一下。 安装的是MySQL社区版&#xff0c;下载地址是www.mysql.com&#xff0c;进入后选择DOWNLOAD页面&#xff0c;选择MySQL Com…

基本的数据类型在16位、32位和64位机上所占的字节大小

1、目前常用的机器都是32位和64位的&#xff0c;但是有时候会考虑16位机。总结一下在三种位数下常用的数据类型所占的字节大小。 数据类型16位(byte)32位(byte)64位(byte)取值范围char111-128 ~ 127unsigned char1110 ~ 255short int / short222-32768~32767unsigned short222…

HarmonyOS实战开发-自定义通知角标、如何设定应用的桌面图标角标的功能。

介绍 本示例主要展示了设定应用的桌面图标角标的功能&#xff0c;使用ohos.notificationManager 接口&#xff0c;进行桌面角标的设置&#xff0c;通知的发送&#xff0c;获取等。 效果预览 使用说明 在使用本应用时&#xff0c;需安装并启动仿桌面应用&#xff1b;在主界面…

LeetCode 57—— 插入区间

阅读目录 1. 题目2. 解题思路3. 代码实现 1. 题目 2. 解题思路 第一步&#xff0c;我们先寻找新区间和原始区间列表的重叠部分。 假设新区间为 [ x 1 , x 2 ] [x_1, x_2] [x1​,x2​]&#xff0c;原始区间列表中的其中一个区间为 [ y 1 , y 2 ] [y_1, y_2] [y1​,y2​]&…

PostgreSQL入门到实战-第三十弹

PostgreSQL入门到实战 PostgreSQL教程网站官网地址PostgreSQL概述更新计划 PostgreSQL教程网站 https://www.postgresqltutorial.com/ 官网地址 声明: 由于操作系统, 版本更新等原因, 文章所列内容不一定100%复现, 还要以官方信息为准 https://www.postgresql.org/PostgreS…

【数据工具】ArcGIS批量出图工具箱

工具下载链接&#xff1a;数据下载链接 我们在使用Arcgis制图的过程中&#xff0c;经常会遇到需要大量出图的情况&#xff0c;如何将做好的图批量导出jpg是一件令人头疼的问题。 今天小编就给大家分享俩个ArcGIS批量出图的工具箱&#xff0c;一个可以批量导出图层为jpg&#…

运筹说 第112期 | M/M/s等待制排队模型

通过上期学习&#xff0c;大家已经了解了排队论中的一些基本概念&#xff0c;以及生灭过程和Poisson过程。 那么本期小编将基于这些基本原理&#xff0c;为大家介绍M/M/s混合制排队模型&#xff0c;包括单服务台模型和多服务台模型&#xff0c;介绍模型的概念以及推导过程等内容…

PoE 技术

1 PoE 技术产生背景 随着 WLAN 、 VoIP 、网络视频监控等新业务的飞速发展,大量的无线 LAN 访问点、 IP 电话、 IP 网络摄像头等基于 IP 的终端出现在工业现场。这些设备通常数量众多、位置特殊 、 布线复杂、设备取电困难,其实施部署不仅消耗大量人力物力,…

【数据结构与算法】搜索算法(深度优先搜索 DFS和广度优先搜索 BFS)以及典型算法例题

目录 搜索算法&#xff08;深度优先搜索DFS和广度优先搜索BFS&#xff09;以及典型算法例题深度优先搜索 &#xff08;Depth First Search 简称 DFS&#xff09;DFS 的设计步骤深度优先搜索&#xff08;DFS&#xff09;算法例题例题一&#xff1a;N皇后问题例题二&#xff1a;路…

FreeRTOS学习 -- FreeRTOSConfig.h介绍

一、FreeRTOSConfig.h文件 FreeRTOS 的系统配置文件为 FreeRTOSConfig.h&#xff0c;在此配置文件中可以完成 FreeRTOS 的裁剪和配置。 FreeRTOS 的配置基本是通过在 FreeRTOSConfig.h 中使用“#define”这样的语句来定义宏定义实现的。在 FreeRTOS 的官方 demo 中&#xff0…

CentOS7离线升级OpenSSH_8.8p1

一、环境 centos7.9,升级openssh到8.8p1最新版本 二、下载升级包 # openssl和zlib为相关依赖 wget https://cdn.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-8.8p1.tar.gz wget https://www.openssl.org/source/openssl-1.1.1j.tar.gz wget http://www.zlib.net/zl…

mysql dll文件的缺失和Can‘t connect to MySQL server on ‘localhost‘ (10061)

个人笔记&#xff08;整理不易&#xff0c;有帮助&#xff0c;收藏点赞评论&#xff0c;爱你们&#xff01;&#xff01;&#xff01;你的支持是我写作的动力&#xff09; 笔记目录&#xff1a;学习笔记目录_pytest和unittest、airtest_weixin_42717928的博客-CSDN博客 个人随笔…

数学:人工智能学习之路上的“拦路虎”及其背后的奥秘

在人工智能的浪潮席卷全球的今天&#xff0c;越来越多的人开始涉足这一领域&#xff0c;以期掌握其核心技术&#xff0c;为未来的科技发展贡献力量。然而&#xff0c;在学习的道路上&#xff0c;许多人却遇到了一个不小的挑战——数学。为何数学会成为学习人工智能的“拦路虎”…