c++重中之重:“换个龟壳继续套娃“:运算符重载等的学习

news2024/12/25 13:22:19

 

 

文章目录

  • 前言
  • 一.运算符重载
  • 二.const成员
  • 三.取地址重载
  • 总结

 


前言

上一期我们讲到类的6个默认构造函数中的拷贝构造函数,这一期我们继续往下讲,当然难点肯定是运算符重载了。


 

一、运算符重载

运算符重载是c++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数相似。

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

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

注意:

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

2.重载操作符必须有一个类类型参数

3.用于内置类型的运算符,其含义不能改变。例:内置的整形 + ,不能改变+的含义,比如把加法弄成乘法之类的。

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

5.有五个运算符是不能重载的。1 .*(点星) 2  ::(域名限定符)   3  sizeof    4  ?:(三目操作符) 5  . (成员访问操作符)

class Date
{
public:
	Date(int year = 10, int month = 10, int day = 10)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void print()
	{
		cout << _year << "年" << _month << "月" << _day << "日" << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1(2023,2,10);
	Date d2(2023,2,5);
	d2.print();
	return 0;
}

 像上面的d1和d2两个参数该如何比较大小呢?以前在C语言我们通常写一个函数是传两个日期的地址过去然后挨个用指针访问去比较最后返回布尔值,这样会非常的麻烦,而c++的运算符重载正好解决了这个问题。:

class Date
{
public:
	Date(int year = 10, int month = 10, int day = 10)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void print()
	{
		cout << _year << "年" << _month << "月" << _day << "日" << endl;
	}
	bool operator==(const Date& d)
	{
		return _year == d._year
			&& _month == d._month
			&& _day == d._day;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1(2023,2,10);
	Date d2(2023,2,10);
	cout << (d1 == d2) << endl;
	return 0;
}

 b73573bb15e54fc49d16643fcf22e4a7.png

b23f10412c9b4eadb52588f6ed02512d.png 通过上面的代码和图片大家应该可以看到运算符重载对于自定义类型有多方便,而运算符重载的规则我们也讲过,那么写到类外什么样子呢?

(由于类外不可访问类内私有成员可以先将私有成员改为共用或者知道友元函数的用友元)

b0f8108e45284803a3b98a11cf9c946b.png

类外的区别就是多一个参数,因为在类内有this指针。 cout打印d1==d2加括号的原因是流插入操作符的优先级高于==。

符号>的重载:

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

 715e47c783f949e99cd1b2f37a308302.png

符号<=的重载:

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

 我们可以发现运算符很多都是实现一两个其他的就可以复用了。小于等于不就是大于的取反吗,只需要知道类内函数有隐藏的参数this默认指向第一个操作数即可。

符号<:

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

 赋值运算符重载

赋值运算符的重载格式:

1.参数类型 const T&,传递引用可以提高传参效率。

2.返回值类型T& ,返回引用可以提高返回的效率,有返回值的目的是为了实现连续赋值

3.检测自己给自己赋值(因为两个一样的变量再去赋值会消耗空间)

4.返回*this 要复合连续赋值的含义

注意:赋值运算符的重载并不是强制要求参数为&,这里要和拷贝构造区分,赋值运算符即使用传值调用也可以使用不会发生无穷调用因为在传自定义类型参数的时候先拷贝构造一个临时变量然后将这个变量赋值给变量即可。

Date& operator=(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
		return *this;
	}

 d4ddac9956ab4c6bb7c274895c74df25.png

 一般来说赋值给另一个对象是不需要返回值的,但是为了实现连续赋值那么就必须返回被赋值的那个变量,由于被赋值的对象不会被销毁,所以为了不调用拷贝构造函数浪费空间直接使用引用返回即可。如果有人写成d1= d1这样的代码,那么不就白白的浪费了空间吗,所以我们直接判断一下

Date& operator=(const Date& d)
	{
		if (this != &d)
		{
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}
		return *this;
	}

this是左操作数的地址,&d是右操作数的地址,这样的好处就是即使赋值时出现操作数一样的情况也不会白白浪费空间。

注意:运算符的顺序不是从右往左也不是从左往右,这是要看操作符的结合性的。

比如: += 是从右往左开始的   + 是从左往右开始的

我们之前说过,类的6个默认函数即使我们不写编译器也会写一个默认的,那么默认的能完成赋值重载的任务吗?这个问题和拷贝赋值是一样的,对于内置类型编译器可以完成赋值,但是对于像栈那样需要开不同空间的必须我们手动去写一个赋值重载。

c03373ebfcbe484c9dceb7bddca036ef.png

 前面讲拷贝构造的时候忘记了一个细节,那就是向上图中红色框起来的也是拷贝构造,有些人会有疑问,这里不是用赋值重载了吗?其实并不是,赋值重载的调用是针对两个已经实例化好的或定义的对象,而像上图中d5还没有定义出来是在实例化的过程中,是用d1初始化d5,用一个对象初始化一个对象用的是拷贝构造。

下面我们利用运算符重载实现一个计算日期的小程序,小程序的功能包括:日期+天数,日期+=天数,日期-天数,日期-=天数,日期的前置++后置++,日期的前置--后置--,日期-日期相差多少天,下面先展示源代码然后我们一个函数一个函数讲解:

class Date
{
public:
	Date(int year = 2023, int month = 2, int day = 10)
	{
		if (year > 0 && (month >= 1 && month <= 12) && (day > 0 && day <= GetMonthDay(year, month)))
		{
			_year = year;
			_month = month;
			_day = day;
		}
		else
		{
			cout << "日期不合法:" << endl;
			exit(-1);
		}
	}
	void Print()
	{
		cout << _year << "年" << _month << "月" << _day << "日" << endl;
	}
	bool operator==(const Date& d)
	{
		return _year == d._year
			&& _month == d._month
			&& _day == d._day;
	}
	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)
	{
		return !(*this < d);
	}
	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);
	}
	Date& operator=(const Date& d)
	{
		if (this != &d)
		{
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}
		return *this;
	}
	int GetMonthDay(int year, int month)
	{
		int MonthArray[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
		if (month == 2 && (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
		{
			return 29;
		}
		else
		{
			return MonthArray[month];
		}
	}
	//日期 += 天数
	Date& operator+=(int day)
	{
		if (day < 0)
		{
			*this -= -day;
			return *this;
		}
		_day += day;
		while (_day > GetMonthDay(_year, _month))
		{
			_day -= GetMonthDay(_year, _month);
			_month++;
			if (_month == 13)
			{
				_year++;
				_month = 1;
			}
		}
		return *this;
	}
	//日期 + 天数
	Date operator+(int day)
	{
		Date tmp(*this);
		tmp += day;
		return tmp;
	}
	//前置++
	Date& operator++()
	{
		*this += 1;
		return *this;
	}
	//后置++
	Date operator++(int)
	{
		Date tmp(*this);
		*this += 1;
		return tmp;
	}
	//日期 -= 天数
	Date& operator-=(int day)
	{
		if (day < 0)
		{
			*this += -day;
			return *this;
		}
		_day -= day;
		while (_day <= 0)
		{
			_month--;
			if (_month == 0)
			{
				_year--;
				_month = 12;
			}
			_day += GetMonthDay(_year, _month);
		}
		return *this;
	}
	//日期 - 天数
	Date operator-(int day)
	{
		Date tmp(*this);
		tmp -= day;
		return tmp;
	}
	//前置--
	Date& operator--()
	{
		*this -= 1;
		return *this;
	}
	//后置--
	//int参数 仅仅是为了占位,根前置重载区分
	Date operator--(int)
	{
		Date tmp(*this);
		*this -= 1;
		return tmp;
	}
	//日期相减(得到的是天数)
	int operator-(const Date& d)
	{
		Date Max = *this;
		Date Min = d;
		int flag = -1;
		if (*this < d)
		{
			Max = d;
			Min = *this;
			flag = 1;
		}
		int n = 0;
		while (Max != Min)
		{
			n++;
			Min++;
		}
		return n * flag;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1(2023, 12, 3);
	Date d2(2023, 6, 4);
	//cout << (d1 > d2) << endl;
	/*d1 = --d2;
	d1.Print();
	d2.Print();*/
	//d2.Print();
	//cout << (d1 - d2) << endl;
	d2 =d1 - -100;
	d2.Print();
	return 0;
}

 首先,我们在构造函数中初始化的时候要确保日期是合法的,不能出现月数小于0或者大于12的,并且天数要大于0小于当月最大天数,所以我们在构造函数中加了一个判断,当日期不合法时就输出"日期不合法"并且退出程序。

int GetMonthDay(int year, int month)
	{
		int MonthArray[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
		if (month == 2 && (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
		{
			return 29;
		}
		else
		{
			return MonthArray[month];
		}
	}

因为我们计算日期的时候必须知道每个月是多少天而且还有闰年二月是29天的情况,所以我们写了一个函数得到每个月的天数,数组有13个是因为数组是从0开始我们为了方便直接在第一个位置加一个0即可。

接下来我们讲解日期+=天数:

Date& operator+=(int day)
	{
		if (day < 0)
		{
			*this -= -day;
			return *this;
		}
		_day += day;
		while (_day > GetMonthDay(_year, _month))
		{
			_day -= GetMonthDay(_year, _month);
			_month++;
			if (_month == 13)
			{
				_year++;
				_month = 1;
			}
		}
		return *this;
	}

 f200449ddde44486beb7fbb5166b9385.png

在这里由于不确定要加多少天如果加1000天那么就要重复上图的步骤所以这是一个循环,当天数大于当月最大天数的时候就进入循环,需要注意的是当月数加到13就说明越界了要及时改为合法月数。因为+=就是会改变本身的值,并且在函数结束后日期也没有被销毁,所以我们采用传引用的方式减少拷贝构造的消耗。判断天数是否小于0是因为我们不知道有人会不会写成-数,如果是负数那就是-=一个正数。

Date operator+(int day)
	{
		Date tmp(*this);
		tmp += day;
		return tmp;
	}

 日期+天数那么是不会改变本身的,所以我们需要拷贝构造一个变量,这时候直接复用+=操作符即可,由于tmp是函数中的临时变量,函数结束就会销毁,所以不能采用传引用的方式。

//前置++
	Date& operator++()
	{
		*this += 1;
		return *this;
	}

 前置++是先++在使用,所以直接+1返回即可。

//后置++
	Date operator++(int)
	{
		Date tmp(*this);
		*this += 1;
		return tmp;
	}

 后置++是先使用再++,也就是说我们必须用一个变量接收开始的日期,然后自己+1返回开始没有+1的那个值即可,由于这个值是临时变量所以只能用传值返回。需要注意的是,编译器区分前置++和后置++的点是后置++的参数有一个int,这个int是占位符没有实际作用,也不用写参数,写一个int即可。

//日期 -= 天数
	Date& operator-=(int day)
	{
		if (day < 0)
		{
			*this += -day;
			return *this;
		}
		_day -= day;
		while (_day <= 0)
		{
			_month--;
			if (_month == 0)
			{
				_year--;
				_month = 12;
			}
			_day += GetMonthDay(_year, _month);
		}
		return *this;
	}

01633d9128e8403fa9ffeef207135c42.png  

 需要注意的是减去天数后如果大于0就说明本月的天数够用不需要向上个月借,等于0也需要借因为没有2月0日,为了让借到的天数是上个月的所以月份--后再加上借的天数,与+=同理都要判断day是否为负数,为负数就变成了+上一个正数,那为什么+和-我们没有判断呢?因为+和-我们是用+=和-=复用的。

//日期 - 天数
	Date operator-(int day)
	{
		Date tmp(*this);
		tmp -= day;
		return tmp;
	}

 这里与+一样复用就可以。前置--和后置--也与++一样。

//日期相减(得到的是天数)
	int operator-(const Date& d)
	{
		Date Max = *this;
		Date Min = d;
		int flag = -1;
		if (*this < d)
		{
			Max = d;
			Min = *this;
			flag = 1;
		}
		int n = 0;
		while (Max != Min)
		{
			n++;
			Min++;
		}
		return n * flag;
	}

日期相减实现起来也很简单,我们以之前的为负,以后的为正,先定义两个变量Max和Min来存放两个日期,我们默认是第一个日期大于第二个日期,当第一个大于第二个日期的时候就说明是之前的那么让flag为负,如果第一个日期小于第二个日期,就让flag为正。然后我们用n来记录天数,当两个日期不相等就进入循环,让n和小的那个日期自加直到相等我们就能计算出有多少天了。

那么我们每次调用函数去打印日期是不是不方便呢?能不能直接用cout打印日期呢?答案是可以的,我们通过重载<<运算符即可完成。我们现在类中声明然后再类外实现。

6064ae0d669b4323a5d7e71a647448af.png 

那么我们写了一个为什么不能调用呢? b6e62ec09ff04e9cba9f808ba157052b.png

 我们只能通过调用函数的方式去调用,和我们想的并不一样,这怎么办呢?我们用cout不能直接调用的原因是操作符的左边是左操作数,右边是右操作数,而我们常用的打印习惯是右操作数,那么我们先来看一下左操作数是否能正确调用:

bcacee1a61bb4101aedb277509e15eb4.png

 我们发现是可以正确调用的,但是很奇怪我们喜欢写到右边。解决这个问题之前我们要先知道运算符重载在类中第一个操作符是*this,而像我们那样的写法很明显out是右操作数了,我们要的是out去作为左操作数,想要让out成为左操作数将运算符重载写到外面了不就解决了吗,因为外面是没有*this的。

b60aab9d83c04ebc80596f723c580eb7.png

但是当我们写到定义在类外发现不能访问类内的成员了,这里的解决方式有多个,我们讲两个简单的即可,第一个将类内私有改为公有如下图:

9a47ed1037e541b78940a6b8ee0b30a3.png

第二个是用友元函数,我们将这个函数设为类的友元就可以访问类的所有成员了。

6e43dddbc8af4e16b51f36bd7a1783ca.png aff0748b87b9484194e6bbd1729be082.png

 f46b26264e5544a0ade02787822004b5.png

 为什么编译器的cout支持多个打印我们的不可以呢?这是因为我们没有返回值,我们应该要将out返回这样就能连续打印了,因为out出了作用域没有被销毁所以我们可以返回其引用。

09ae26e18ef54f48be4b891a56e38ae9.png 4c2c15e2291d46de8afbb4d631300e10.png

这样就解决了打印自定义类型的问题,接下来我们再重载一下cin,与cout一样只需要改一下参数即可。

49601924b86143b88bff80e7463e976a.png

5ee6ff12334b495a95d9160a666f6aa9.png 为什么输入的参数d我们不加const了呢?这是因为我们输入会改变const的值如果加了const就不能改变了。

在这里需要注意一下,类里面的短小函数,适合做内联的函数,直接是在类里面定义的。

const成员

将const修饰的“成员函数”称之为const成员函数,const修饰类成员函数,实际修饰该成员隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改。

class A
{
public:
	void Print()
	{
		cout << _a << endl;
	}
private:
	int _a;
};
int main()
{
	/*A aa;
	aa.Print();*/
	const A aa; //权限的放大
	aa.Print();
	return 0;
}

419325d00e9741ea89b0be8ef9ccea3a.png

在这里为什么会报错呢?因为aa的类型是const A* ,而传递给this指针后变成了A* ,所以这里是权限的放大,想要解决只需要给this指针也用const修饰,如下图:

ac6188a4b63441909d9c44a91bebe1e8.png

这里函数后面的const修饰的是this指针,让this指针变成了const A*。

1c65ac6bc2db4be3a0000be3e684a9ca.png而上图是权限的缩小,权限的缩小是没有问题的,调用Func函数从A*变成了const A*.

总结:内部不改变成员变量的成员函数,最好加上const,const对象和普通对象都可以调用,比如下面的代码:

#include <assert.h>
class Array
{
public:
	int& operator[](int i)
	{
		assert(i < 10);
		return _a[i];
	}
	const int& operator[](int i) const
	{
		assert(i < 10);
		return _a[i];
	}

private:
	int _a[10];
	int _size;
};
void Func(const Array& d)
{
	for (int i = 0; i < 10; i++)
	{
		cout << d[i] << " ";
	}
}
int main()
{
	Array ay;
	for (int i = 0; i < 10; i++)
	{
		ay[i] = i * 10;
	}
	for (int i = 0; i < 10; i++)
	{
		cout << ay[i] << " ";
	}
	Func(ay);
	return 0;
}

取地址重载

取地址重载和赋值运算符重载一样都会由编译器自己生成,当然有需求也可以自己去写。

939165b7ce584f3c9f632f1309239443.png

本来自定义类型用运算符必须自己重载,但是赋值运算符和取地址重载编译器生成的就够用。

9d550cff008d408e805821ecead76595.png 当然如果我们不想让别人获取我们的地址我可可以返回一个假地址如上图所示

0a454e68b5bd492cb93fad09dc768b7d.png

以上就是取地址重载的用法,总之不是非常必要是不用去自己写取地址重载和const取地址重载的。 

 


总结

学会运算符重载是学习c++必备的技能,c++独特的就是自定义类型,而运算符重载可以解决自定义类型使用运算符的问题。

 

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

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

相关文章

笑死,面试官又问我SpringBoot自动配置原理

面试官&#xff1a;好久没见&#xff0c;甚是想念。今天来聊聊SpringBoot的自动配置吧&#xff1f; 候选者&#xff1a;嗯&#xff0c;SpringBoot的自动配置我觉得是SpringBoot很重要的“特性”了。众所周知&#xff0c;SpringBoot有着“约定大于配置”的理念&#xff0c;这一…

亿级高并发电商项目-- 实战篇 --万达商城项目 四(Dashboard服务、设置统一返回格式与异常处理、Postman测试接口 )

专栏&#xff1a;高并发---前后端分布式项目 &#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是小童&#xff0c;Java开发工程师&#xff0c;CSDN博客博主&#xff0c;Java领域新星创作者 &#x1f4d5;系列专栏&#xff1a;前端、Java、Java中间件大全、微信小程序、…

Spring-事务2

文章目录前言一、事务的特性&#xff08;ACID&#xff09;二、事务的隔离级别三、spring中的事务平台事务管理器.事务定义ISOLation_XXX&#xff1a;**事务隔离级别.**PROPAGATION_XXX&#xff1a;**事务的传播行为**.事务状态关系&#xff1a;四、使用XML文件配置事务1、 搭建…

2023前端面试题——JS篇

1.判断 js 类型的方式 1. typeof 可以判断出’string’,‘number’,‘boolean’,‘undefined’,‘symbol’ 但判断 typeof(null) 时值为 ‘object’; 判断数组和对象时值均为 ‘object’ 2. instanceof 原理是 构造函数的 prototype 属性是否出现在对象的原型链中的任何位置 …

Vue原理解析

文章目录1. VUE的响应式原理1.1 ViewModel1.2 双向绑定的基本原理1.3 什么是响应性1.4 Vue 中的响应性是如何工作的2. Vue 渲染机制2.1 虚拟 DOM2.2 渲染管线2.3 带编译时信息的虚拟 DOM2.3.1 静态提升2.3.2 修补标记 Flags2.3.3 树结构打平2.3.4 对 SSR 激活的影响1. VUE的响应…

Zookeeper安装和基本使用

目录标题一、下载二、安装三、启动客户端测试四、使用zk一、下载 注意&#xff1a;自zk3.5.5版本以后&#xff0c;已编译的jar包&#xff0c;尾部有bin&#xff0c;应该使用的是apache-zookeeper-3.8.0-bin.tar.gz。&#xff0c;因此在下载高版本时&#xff0c;因该下载后缀带b…

华为手表开发:WATCH 3 Pro(5)点击按钮弹窗

华为手表开发&#xff1a;WATCH 3 Pro&#xff08;5&#xff09;点击按钮弹窗初环境与设备创建项目认识目录结构修改首页 -> 新建按钮 “ 按钮 ”文件名&#xff1a;**index.hml**引用包&#xff1a;system.prompt点击结果初 鸿蒙可穿戴开发 希望能写一些简单的教程和案例…

三大指标继续狂飙!重庆啤酒:不惧强弱分化加剧,深耕高端市场

十多年前&#xff0c;重庆啤酒因为9个跌停而被一片唱衰&#xff0c;资本市场经典的“关灯吃面”典故自此出现&#xff0c;被股民沿用至今。不过自2020年&#xff0c;重庆啤酒开始逆转走势&#xff0c;股价连续上涨。2021年重庆啤酒营收突破百亿大关&#xff0c;净赚11.66亿元&a…

关于小程序,你想知道的这些

近年来&#xff0c;各大平台纷纷上架小程序&#xff0c;迎来了小程序的爆发式增长。今天就来跟大家简单分享一下小程序基本的运行机制和安全机制。 小程序的由来 在小程序没有出来之前&#xff0c;最初微信WebView逐渐成为移动web重要入口&#xff0c;微信发布了一整套网页开…

自监督表征学习方法——BYOL(Bootstrap Your Own Latent)

自监督表征学习方法——BYOL(Bootstrap Your Own Latent) 参考文献&#xff1a;《Bootstrap Your Own Latent A New Approach to Self-Supervised Learning》 1.前言背景 学习良好的图像表示是计算机视觉中的一个关键挑战&#xff0c;因为它允许对下游任务进行有效的训练。许…

POE接口电路设计

首先看到PSE端&#xff0c;主要包含PSE芯片&#xff0c;MOS管&#xff08;有些PSE芯片MOS管是集成在芯片里面的&#xff09;&#xff0c;自恢复保险丝&#xff0c;还有TVS管&#xff0c;一般这个TVS管保护电压是58V的。这个电阻是用来检测POE传输的电流的&#xff0c;一般是0.几…

vue2 diff算法及虚拟DOM

概括&#xff1a;diff算法&#xff0c;虚拟DOM中采用的算法&#xff0c;把树形结构按照层级分解&#xff0c;只比较同级元素&#xff0c;不同层级的节点只有创建和删除操作。 一、虚拟DOM (1) 什么是虚拟DOM&#xff1f; 虚拟 DOM (Virtual DOM&#xff0c;简称 VDOM) 是一种…

KDDAC-10kV 电缆交流耐压及振荡波局放测试系统

一、概述 目前对电力电缆检修的管理&#xff0c;主要是依据《电力设备交接和预防性试验规程》所规定的项目和试验周期&#xff0c;定期在停电状态下进行绝缘性能试验。其中变频串联谐振试验由于试验状况接近电缆的运行工况&#xff0c;因此成为国内目前应用广泛的试验方法。 …

社科院与杜兰大学中外合作办学金融管理硕士——30+的年龄在职读研有必要吗?

说起读研&#xff0c;年龄在什么区间最合适呢&#xff1f;上次有位咨询的同学反馈年龄已经快35岁了&#xff0c;有一份不错的工作&#xff0c;但又不甘心止步于此&#xff0c;想要通过提升学历升职加薪&#xff0c;但又纠结自己是否能静下心来学习、是否能顺利毕业、拿到的证书…

[HSCSEC 2023] rev,pwn,crypto,Ancient-MISC部分

比赛后有讲解&#xff0c;没赶上&#xff0c;前20比赛完1小时提交WP&#xff0c;谁会大半夜的起来写WP。总的感觉pwn,crypto过于简单&#xff0c;rev有2个难的不会&#xff0c;其它不是我的方向都感觉过于难&#xff0c;一个都没作。revDECOMPILEONEOONE入门题&#xff0c;一个…

12 循环神经网络(基础篇) Basic RNN

文章目录问题引入关于权重权重共享RNN CellRNN原理RNN计算过程代码实现RNN Cell维度说明代码RNN维度说明NumLayers说明计算过程代码参考实例问题分析多分类问题代码RNN CellRNN改进Embedding网络结构Embedding说明Linear说明代码课程来源&#xff1a; 链接课程文本参考&#xf…

前端react面试题指南

概述下 React 中的事件处理逻辑 抹平浏览器差异&#xff0c;实现更好的跨平台。避免垃圾回收&#xff0c;React 引入事件池&#xff0c;在事件池中获取或释放事件对象&#xff0c;避免频繁地去创建和销毁。方便事件统一管理和事务机制。 为了解决跨浏览器兼容性问题&#xff0…

CSS基础:盒子模型和浮动

盒子模型 所有HTML元素可以看作盒子&#xff0c;在CSS中&#xff0c;"box model"这一术语是用来设计和布局时使用 CSS盒模型本质上是一个盒子&#xff0c;封装HTML元素。 它包括&#xff1a;外边距&#xff08;margin&#xff09;&#xff0c;边框&#xff08;bord…

操作系统考试突击复习笔记

0 基础概念补充特权命令&#xff1a;有特殊权限的指令&#xff0c;比如清内存、置时钟、分配系统资源、修改虚拟内存的段表和页表&#xff0c;修改用户的访问权限。系统调用&#xff1a;操作系统为应用程序提供的使用接口&#xff0c;可以理解为一种可供应用程序调用的特殊函数…

Elasticsearch7.8.0版本进阶——数据写流程

目录一、数据写流程概述二、数据写流程步骤2.1、数据写流程图2.2、数据写流程步骤&#xff08;新建索引和删除文档所需要的步骤顺序&#xff09;2.3、数据写流程的请求参数一、数据写流程概述 新建、删除索引和新建、删除文档的请求都是写操作&#xff0c; 必须在主分片上面完…