【C++心愿便利店】No.7---C++之运算符重载

news2024/11/16 3:26:52

文章目录

  • 前言
  • 一、运算符重载的引用
  • 二、运算符重载
  • 三、赋值运算符重载
  • 四、日期类的实现
  • 五、const成员
  • 六、取地址及const取地址操作符重载


前言

在这里插入图片描述

👧个人主页:@小沈YO.
😚小编介绍:欢迎来到我的乱七八糟小星球🌝
📋专栏:C++ 心愿便利店
🔑本章内容:运算符重载
记得 评论📝 +点赞👍 +收藏😽 +关注💞哦~


提示:以下是本篇文章正文内容,下面案例可供参考

一、运算符重载的引用

本章将以日期类为例进行展开叙述

通常比较两个操作数的大小,会写成下述方式:

int main()
{
	int i = 1, j = 2;
	i < j;
	return 0;
}

但是对于日期类采用上述方式会发生报错:

class Date
{
public:
	Date(int year = 2023, int month = 9, int day = 25)
	{
		_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, 10, 1);
	Date d2(2022, 2, 15);
	d1.Print();
	d2.Print();
	
	d1 < d2;
	
	return 0;
}

在这里插入图片描述
🌟因为日期类是我们自己定义的,属于一种自定义类型,它的大小比较方式,编译器是不知道的,而像int等内置类型,这是原生语言定义的,知道规则来比较,可以直接用<、>去比较两个内置类型变量的大小,但自定义类型不可以哦

最常见的解决方式:

🌟创建一个函数来通过一 一对比年月日来实现日期类的比较,不过会出现关于私有的问题,这个函数是写在类外面的,意味着,日期类的成员变量是private私有的,在类外面就无法访问,所以在这个函数里面是访问不到类对象中的_year、_month、_day,所以x1._year等都是错误的会发生报错,要想实现该函数的功能,可以采用下面3种方法:

class Date
{
public:
	Date(int year = 2023, int month = 9, int day = 25)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void Print()
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}
//private:
	int _year;
	int _month;
	int _day;
};
bool DateLess(const Date& x1, const Date& x2)
{
	if (x1._year < x2._year)
	{
		return true;
	}
	else if (x1._year == x2._year && x1._month < x2._month)
	{
		return true;
	}
	else if (x1._year == x2._year && x1._month == x2._month&&x1._day<x2._day)
	{
		return true;
	}
	else
	{
		return false;
	}
}
int main()
{
	Date d1(2023, 10, 1);
	Date d2(2022, 2, 15);
	d1.Print();
	d2.Print();
	DateLess(d1, d2);
	return 0;

在这里插入图片描述
🌟但是对于这种函数写法相比于直观的<、>来看显然不是很直观,对于不清楚的other来说,读代码是很困难的,所以就引入了运算符重载

二、运算符重载

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

函数名字为:关键字operator后面接需要重载的运算符符号。
函数原型:返回值类型 operator操作符(参数列表)

bool operator<(const Date& x1, const Date& x2)
{
	if (x1._year < x2._year)
	{
		return true;
	}
	else if (x1._year == x2._year && x1._month < x2._month)
	{
		return true;
	}
	else if (x1._year == x2._year && x1._month == x2._month&&x1._day<x2._day)
	{
		return true;
	}
	else
	{
		return false;
	}
}
int main()
{
	Date d1(2023, 10, 1);
	Date d2(2022, 2, 15);
	
	//cout<<d1<d2<<endl;
	至于为什么不写成cout<<d1<d2<<endl是因为<<的优先级高于<
	
	d1<d2与operator<(d1<d2)本质上都是调用运算符重载,所以两者写法是等价的只不是一个显示调用,一个没有显示调用
	
	cout << (d1 < d2) << endl;
	cout << (operator<(d1, d2)) << endl;
	
	return 0;
}

🌟上述代码就是对<运算符的一个重载,此时两个日期类对象就可以直接用<来比较大小,d1 < d2本质上就是调用运算符重载函数,此外,还需要解决一个问题:上面的运算符重载函数是写在类外面的,日期类的成员变量是private私有的,该运算符重载函数还是不能用。

🌟注意:

  • 🌏不能通过连接其他符号来创建新的操作符:比如operator@
  • 🌏重载操作符必须有一个自定义类型参数
int x1, int x2)都是内置类型是不可以的规定必须有一个自定义类型的参数
也就是说只能对自定义类型进行重载,内置类型不可以
bool operator<(int x1, int x2)
{
	if (x1._year < x2._year)
	{
		return true;
	}
	else if (x1._year == x2._year && x1._month < x2._month)
	{
		return true;
	}
	else if (x1._year == x2._year && x1._month == x2._month && x1._day < x2._day)
	{
		return true;
	}
	else
	{
		return false;
	}
}
  • 🌏用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不能改变其含义
  • 🌏作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this
d1<d2两个操作数是不可以随意换位置的,左操作数就是第一个参数(this),右操作数就是第二个参数(d)
d1.operator<(d2)

bool operator==(Date* this, const Date& d2)
这里需要注意的是,左操作数是this,指向调用函数的对象(和上面一个意思)

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;
	}
}
int main()
{
	Date d1(2023, 10, 1);
	Date d2(2022, 2, 15);
	cout << (d1 < d2) << endl;
	cout << (d1.operator<(d2)) << endl;
	成员函数---符合调用规则因为有一个是隐含的参数(d1.operator(d2)return 0;
}
——————————————————————————————————————————————————————————————————————————————————
类外面定义函数
bool operator<(const Date& x1, const Date& x2)
{
	if (x1._year < x2._year)
	{
		return true;
	}
	else if (x1._year == x2._year && x1._month < x2._month)
	{
		return true;
	}
	else if (x1._year == x2._year && x1._month == x2._month && x1._day < x2._day)
	{
		return true;
	}
	else
	{
		return false;
	}
}
int main()
{
	Date d1(2023, 10, 1);
	Date d2(2022, 2, 15);
	cout << (d1 < d2) << endl;
	cout << (operator<(d1, d2)) << endl;
	return 0;
}
  • 🌏不能改变操作符的操作数个数,一个操作符是几个操作数,那么重载的时候就有几个参数
  • 🌏(.* 和 *不一样 * 是可以重载的) 、 (域作用限定符 ::)、 sizeof 、(三目运算符?:) 、(对象变量取成员 .) 注意以上5个运算符不能重载。这个经常在笔试选择题中出现选择题。

三、赋值运算符重载

🌟 首先要区分赋值运算符和拷贝构造:

  • 赋值:两个已经存在的对象进行拷贝
  • 拷贝构造:一个已经存在的对象去初始化另一个对象
Date d1(2023, 10, 1);
Date d2(2023, 10, 7);
d1 = d2;     --->调用赋值运算符重载
Date d3 = d1;      --->调用拷贝构造函数;或者写成这种也是拷贝构造Date d3(d1);
1 .赋值运算符重载格式:
  • 参数类型:const T&,传递引用可以提高传参效率
  • 返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值
  • 检测是否自己给自己赋值
  • 返回*this :要复合连续赋值的含义
Date& operator=(const Data& d)
{
	if (this != &d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
	return *this;
}
2 .赋值运算符只能重载成类的成员函数不能重载成全局函数:

我们可以重载赋值运算符。不论形参的类型是什么,赋值运算符都必须定义为成员函数

class Date
{
public:
 Date(int year = 1900, int month = 1, int day = 1)
 {
 _year = year;
 _month = month;
 _day = day;
 }
 int _year;
 int _month;
 int _day;
};

赋值运算符重载成全局函数,注意重载成全局函数时没有this指针了,需要给两个参数
Date& operator=(Date& left, const Date& right)
{
 if (&left != &right)
 {
 left._year = right._year;
 left._month = right._month;
 left._day = right._day;
 }
 return left;
}

在这里插入图片描述

原因:赋值运算符如果不显式实现,编译器会生成一个默认的。此时用户再在类外自己实现一个全局的赋值运算符重载,就和编译器在类中生成的默认赋值运算符重载冲突了,故赋值运算符重载只能是类的成员函数。

3 .用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝:

用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝。
注意内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值

四、日期类的实现

下面日期类的实现,是通过定义和声明分离来写的所以需要加Date::

一 .重载关系运算符

对于关系运算符有以下几种<、== 、<=、>、>=、!=,因为它们之间存在的逻辑关系,可以通过复用来实现,就比如:想要知道一个数a是否>另一个数b就可以通过判断a是否<=b来实现,所以只需要写一个小于和等于的逻辑之后的复用即可

1 .重载<运算符:
bool Date::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;
	}
}
2 .重载==运算符:
bool Date::operator==(const Date& d)
{
	return _year == d._year
		&& _month == d._month
		&& _day == d._day;
}
3 .重载<=运算符:
bool Date::operator<=(const Date& d)
{
	return *this == d || *this < d;      --->复用<==
}
4 .重载>运算符:
bool Date::operator>(const Date& d)
{
	return !(*this <= d);
}
5 .重载>=运算符:
bool Date::operator>=(const Date& d)
{
	return !(*this < d);
}
6 .重载!=运算符:
bool Date::operator!=(const Date& d)
{
	return !(*this == d);
}
二 .完善日期类

对于日期类的计算,若想知道100天以前或是100天以后是哪一天是非常有价值的,但是一个日期类型和一个整型是可以相加相减吗?当然是可以的,可以通过重载运算符来实现。

1 .获取每个月份的天数:
int Date::GetMonthDay(int year, int month)
{
	static : GetMonthDay肯定会重复调用,每次调用还要定义一遍这个数组会有一定的消耗
	
	const static 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;
	}
	return monthArray[month];   返回的是数组中这个值的临时拷贝
}

注意:对于2月是分闰年和平年的,但是其他月份是固定不变的,所以可以通过一个数组来存放每个月的天数,并且以下标作为每个月的月份所以不是monthArray[12],而是monthArray[13]。其中要把数组定义为静态数组目的是为了防止每次调用还要定义一遍这个数组会有一定的消耗。
此外对于判断闰年和平年这里,还要注意先把month==2写在最前面,因为只有2月是需要判断的

2 .重载+=运算符:
Date& Date::operator+=(int day)
{
	if (day < 0)
	{
		return *this -= (-day);
	}
		_day += day;
		while (_day > GetMonthDay(_year, _month))
		{
			//月进位
			_day -= GetMonthDay(_year, _month);
			_month++;
			if (_month == 13)
			{
				_year++;
				_month = 1;
			}
		}
	return *this;
}

注意:对于if语句为什么复用了-=运算符是因为加一个负的天数,是算多少天以前的日期,所以当天数为负的时候,可以复用-=。

3 .重载+运算符:

+运算符和+=运算符本质是一样的,所以不需要再写一遍,只需要+复用+=运算符就可以了,但是+=运算后等价于a=a+b,a也是会改变的,而+运算符运算后a是不会改变的

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

注意:要计算n+m的最终结果,n和m这两个数值计算后是不会改变的,所以一个日期加天数,原日期是不会改变的,而原日期也就是this指针指向的内容,所以也就是不能修改this指针指向的内容,对此要先利用拷贝构造函数创建一个和*this一模一样的对象tmp,在tmp的基础上去加天数。此外tmp是一个临时变量,出了作用域会销毁,所以不能引用返回

4 .为什么不用+=复用+:

请添加图片描述
注意:上面的复用,只能存在一个,不能同时都去复用,同时存在会出现错误。

5 .重载-=运算符:

对于上述是+=复用+还是+复用+=好给出原因,正因如此,-=和-也是一样的原理,所以先写-=再用-复用-=

Date& Date::operator-=(int day)
{
	这里和上述是一个意思
	if (day < 0)
	{
		return *this += (-day);
	}
	
	_day -= day;
	while (_day <= 0)
	{
		--_month;
		if (_month == 0)
		{
			--_year;
			_month = 12;
		}
		_day += GetMonthDay(_year,  _month);
	}
	return *this;
}
6 .重载-运算符:
Date Date::operator-(int day)
{
	Date tmp(*this);
	tmp -= day;
	return tmp;
}
7 .重载日期-日期:
int Date::operator-(const Date& d)
{
	Date max = *this;
	Date min = d;
	int flag = 1;
	if (max < min)
	{
		max = d;
		min = *this;
		flag = -1;
	}
	int n = 0;
	while (min != max)
	{
		++min;
		++n;
	}
	return n * flag;
}

计算的结果是两个日期之间的天数,所以返回值是int,要想知道两个日期之间相隔的天数,可以设置一个计数器n,让小日期一直加到大日期,就可以知道两个日期之间相隔的天数。

8 .重载前置++和后置++运算符:

++d3 前置++,返回++之后的
++d3 —> d3.operator++()
—————————————————————————————————————————————
d3++ 后置++,返回++之前的
++d3 —> d3.operator++(0) 这里加参数是为了区分前置++和后置++
加一个int参数,进行占位,跟前置++构成函数重载进行区分,本质后置++调用,编译器进行特殊处理

自定义类型用前置++比较好,后置++需要拷贝代价比较大
Date& Date:: operator++()
{
	*this += 1; 复用了+=
	return *this;
}
——————————————————————————————————————————————————————————————————————————————————
Date Date:: operator++(int)
{
	Date tmp(*this);拷贝构造
	*this += 1;
	return tmp;
}

int main()
{
	Date d3(2023, 7, 27);
	下面两者等价不过是前者显式调用,对于后置++或者后置--显式调用需要传个参数不过并无卵用
	Date ret1 = d3.operator++(0);//Date ret1=d3--; 
	ret1.Print();
	d3.Print();
	Date ret2 = ++d3;
	ret2.Print();
	d3.Print();
	return 0;
}
9 .重载前置--和后置--运算符:
Date& Date:: operator--()
{
	*this -= 1;  复用了-=
	return *this;
}
————————————————————————————————————————————————————————————————————————————————
Date Date:: operator--(int)
{
	Date tmp(*this);
	*this -= 1;
	return tmp;
}

int main()
{
	Date d3(2023, 7, 27);
	下面两者等价不过是前者显式调用,对于后置++或者后置--显式调用需要传个参数不过并无卵用
	Date ret1 = d3.operator--(0);//Date ret1=d3--; 
	ret1.Print();
	d3.Print();
	Date ret2 = --d3;
	ret2.Print();
	d3.Print();
	return 0;
}
10 .>>和<<运算符:

对于内置类型可以直接使用<<、>>,编译器可以根据数据的类型进行打印,本质上是因为库中进行运算符重载。但是对于自定义类型,编译器是不知道怎样打印的,所以要想使用<<打印(自定义类型)日期类是要对运算符<<进行重载
在这里插入图片描述
我们在使用C++进行输入输出的时候,会用到cin和cout,它们俩本质上都是对象,cin是istream类实例化的对象,cout是ostream类实例化的对象。
而<<、>>不用像C语言的printf和scanf那样,char对应%c,int对应%d,float对应%f,是因为运算符重载本质上是函数,对这些不同的内置类型,分别进行了封装,在运算符重载的基础上又实现了函数重载,所以<<、>>支持自动识别类型。

11 .重载<<运算符:
Date.h
void operator<<(ostream& cout);//放在类里面的

Date.cpp
void Date::operator<<(ostream& cout)//--->operator(Date* this,ostream& cout)
{
	cout << _year << "-" << _month << "-" << _day << endl;
}

Test.cpp

cout << d1;
d1 << cout;//虽然可以运行,但是不符合使用习惯和价值

当在类中重载<<运算符会发现用cout<<d1打印是会发生报错的,这是因为对于一个双目运算符的重载,它的左操作数(cout)会传递给运算符重载函数的第一个形参(this),右操作数(d1)会传递给运算符重载函数的第二个形参(cout),对于类的成员函数,它的第一个形参是默认的this指针,该指针是日期类类型的指针,和cout的类型不匹(—>operator(Date* this,ostream& cout))。为了解决上述问题,可以写成d1<<cout,此时就相当于d1.operator(cout),会把d1的地址传给this指针,形参再用一个ostream类型的对象来接收cout,虽然可以运行,但是不符合使用习惯和价值。
🌟最好的解决方式:把<<重载成全局函数
把<<重载成全局函数,就不会有默认的this指针,同时,还可以根据需要设置形参的顺序,void operator<<(ostream& out,const Date& d),出了作用域cout还在,所以可以用引用返回。

Date.h
void operator<<(ostream& cout,const Date& d);//全局的

Date.cpp
void operator<<(ostream& cout, const Date& d)
{
	cout << d._year << "-" << d._month << "-" << d._day << endl;
}

Test.cpp
cout << d1;

把<<重载成全局函数是解决了参数问题,但是默认在该全局函数中是访问不到日期类中的私有成员变量,为了解决这个问题,可以把该运算符重载函数设置成友元函数
在这里插入图片描述
🌟友元声明:在日期类里面第一行加上一条下述声明,此时在该全局函数体就可以使用日期类中的私有成员变量。

friend void operator<<(ostream& cout, const Date& d);
此声明不受类中访问限定符的限制

🌟连续的<<

Date.h
ostream& operator<<(ostream& cout,const Date& d);

Date.cpp
ostream& operator<<(ostream& cout, const Date& d)
{
	cout << d._year << "-" << d._month << "-" << d._day << endl;
	return cout;
}
Test.cpp
cout << d1 << d2 << endl;

对于上述cout<<d1,是一个函数调用,返回类型是void,但是对于连续的<<,cout<<d1<<d2<<endl;cout先是作为左操作数打印d1,左向右执行cout<<d1;返回void,后面的d2就会报错,所以要写成ostream& operator<<(ostream& cout, const Date& d),返回一个ostream类型的cout,接着cout作为左操作数再次函数调用打印d2
当然这里改了友元声明也要改成

friend ostream& operator<<(ostream& cout, const Date& d);
12 .重载>>运算符:

希望通过流插入往d里面写入数据,所以不能加const修饰。istream& operator>>(istream& cin, Date& d);

Date.h
istream& operator>>(istream& cin, Date& d);

Date.cpp
istream& operator>>(istream& cin, Date& d)
{
	cin >> d._year >> d._month >> d._day;
	return cin;
}

Test.cpp
cin >> d3;

🌟友元声明

friend istream& operator>>(istream& cin, Date& d);

C++中的流插入和流提取可以完美的支持自定义类型的输入输出

五、const成员

将const修饰的“成员函数”称之为const成员函数,const修饰类成员函数( void Print() const ),实际修饰该成员函数隐含的this指针( void Print(const Date* this) ),表明在该成员函数中不能对类的任何成员进行修改。这样,不仅普通对象可以调用该成员函数(权限的缩小),const对象也能调用该成员函数(权限的平移)。也防止了权限的放大。

const权限问题:
#include<iostream>
using namespace std;
class Date
{
public:
	Date(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void Print()
	{
		cout << "Print()" << endl;
		cout << "year:" << _year << endl;
		cout << "month:" << _month << endl;
		cout << "day:" << _day << endl << endl;
	}
	void Print() const   //  ---> void Print(const Date* this)
	{
		cout << "Print()const" << endl;
		cout << "year:" << _year << endl;
		cout << "month:" << _month << endl;
		cout << "day:" << _day << endl << endl;
	}
private:
	int _year; // 年
	int _month; // 月
	int _day; // 日
};
void Test()
{
	Date d1(2022, 1, 13);
	d1.Print();
	const Date d2(2022, 1, 13);
	d2.Print();
}
int main()
{
	Test();
	return 0;
}

在这里插入图片描述
🌟权限可以缩小可以平移
在这里插入图片描述
🌟权限不可以放大
在这里插入图片描述

总结:

对于关系运算符可以考虑加上const修饰,因为并不会改变对象本身,但是并不是所有的成员函数都要加const修饰,要修改对象成员变量的函数,例如:重载的+=、-=等,是不能加const修饰的,因为会修改成员本身,而成员函数中如果没有修改对象的成员变量,可以考虑加上const修饰,这样不仅普通对象可以调用该成员函数(权限的缩小),const对象也能调用该成员函数(权限的平移)

六、取地址及const取地址操作符重载

#include<iostream>
#include"Date.h"
using namespace std;
Date* Date::operator&()
{
	cout << "Date* operator&()" << endl;
	return this;
}
const Date* Date::operator&()const
{
	cout << "const Date* operator&()const" << endl;
	return this;
	return nullptr;  不想被取到有效地址可以这样写
}
int main()
{
	Date d1(2023,10,1);
	const Date d2(2023,10,1);
	cout << &d1 << endl;
	cout << endl;
	cout << &d2 << endl;
	return 0;
}

在这里插入图片描述

🌟总结:这两个取地址运算符重载函数,又构成函数重载。这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可,只有特殊情况,才需要重载,比如想让别人获取到指定的内容


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

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

相关文章

onlyoffice历史版本功能实现

一&#xff1a;开启客户端配置 如果不开启&#xff0c;回调请求里面的history和changeUrl是空 二&#xff1a;客户端主要实现2个回调函数 1.实现onRequestHistory事件&#xff0c;该事件会在ui点击查看历史的时候发起,用于展示历史列表 关键在于获取到history的内容&#xff…

Vscode进行远程开发

之前用的是pycharm&#xff0c;但是同事说pycharm太重了&#xff0c;连接远程服务器的时候给远程服务器的压力比较大&#xff0c;有时候远程服务器可能都扛不住&#xff0c;所以换成了vscode。 参考博客 手把手教你配置VS Code远程开发工具&#xff0c;工作效率提升N倍 - 知…

【自动驾驶】PETR/PETRv2/StreamPETR论文分析

1.PETR PETR网络结构如下&#xff0c;主要包括image-backbone, 3D Coordinates Generator, 3D Position Encoder, transformer Decoder 1.1 Images Backbone 采用resnet 或者 vovNet,下面的x表示concatenate 1.2 3D Coordinates Generator 坐标生成跟lss类似&#xff0c;假…

从零开始的SRC挖掘

前言 每一次成功的渗透&#xff0c;都有一个非常完备的信息搜集。 大师傅讲的好呀&#xff1a;信息搜集的广度决定了攻击的广度&#xff0c;知识面的广度决定了攻击的深度。 点击此处即可领取282G网络安全学习资料 信息搜集 信息搜集可以从多个领域来看&#xff1a; 公司…

springboot vue 部署至Rocky(Centos)并自启,本文部署是若依应用

概述 1、安装nohup&#xff08;后台进程运行java&#xff09; 2、安装中文字体&#xff08;防止中文乱码&#xff09; 3、安装chrony&#xff08;保证分布式部署时间的一致性&#xff09; 5、安装mysql数据&#xff0c;迁移目录&#xff0c;并授权自启动&#xff1b; 6、安…

基于JavaSpring的学生宿舍管理系统

点击以下链接获取源码&#xff1a; https://download.csdn.net/download/qq_64505944/88407844

Bootstrap网格系统的原理

Bootstrap 提供了一套响应式、移动设备优先的流式网格系统&#xff0c;随着屏幕或视口&#xff08;viewport&#xff09;尺寸的增加&#xff0c;系统会自动分为最多12列。 Bootstrap 网格系统&#xff08;Grid System&#xff09;的工作原理 网格系统通过一系列包含内容的行和…

HRM人力资源管理系统源码

HRM人力资源管理系统源码 运行环境&#xff1a;PHP8.1或以上 MYSQL5.7或以上 php扩展要求 fileinfo imagemagick 功能介绍&#xff1a; 综合仪表板 它通过其综合仪表板提供了员工总数、工单和帐户余额的概览。 您可以轻松访问组织中的缺席者以及详细的公告和预定会议列…

阿里云域名免费配置HTTPS

阿里云域名配置HTTPS - 知乎

零基础也能学会!Linux下安装RStudio工具及实现远程访问的详细指南

前言 RStudio Server 使你能够在 Linux 服务器上运行你所熟悉和喜爱的 RStudio IDE&#xff0c;并通过 Web 浏览器进行访问&#xff0c;从而将 RStudio IDE 的强大功能和工作效率带到基于服务器的集中式环境中。 下面介绍在Linux docker中安装RStudio Server并结合cpolar内网…

JuiceFS 目录配额功能设计详解

JuiceFS 在最近 v1.1 版本中加入了社区中呼声已久的目录配额功能。已发布的命令支持为目录设置配额、获取目录配额信息、列出所有目录配额等。完整的详细信息&#xff0c;请查阅文档。 在设计此功能时&#xff0c;对于它的统计准确性&#xff0c;实效性以及对性能的影响&#…

工业交换机的“自适应”是什么意思?

工业交换机诸多性能指标中&#xff0c;我们常常看见有“自适应”这个指标。它到底是什么意思呢&#xff1f; 自适应也叫自动匹配、自协商&#xff0c;以太网技术发展到100M速率以后&#xff0c;出现了一个如何与原10M以太网设备兼容的问题&#xff0c;自协商技术就是为了解决这…

python中一些代码提速技巧

目录 用set而非list进行查找用dict而非两个list进行匹配查找优先使用for循环而不是while循环循环代替递归用缓存机制加速递归函数用numba加速Python函数使用collections.Counter加速计数使用collections.ChainMap加速字典合并使用map代替推导式进行加速使用filter代替推导式进行…

nacos2.0.2漏洞分析及解决方法

绕过鉴权情况 1. userAgentAuthWhite 设置为true&#xff0c;官方没有还没有解析为啥可以通过设置userAgent可以绕过鉴权 实验一 只要把请求header&#xff1a;User-Agent设置为&#xff1a;Nacos-Server&#xff0c;即可绕过鉴权 实验二 只要把请求header&#xff1a;User…

SpringBoot原理解析篇(一):parent 版本管理

SpringBoot 是由 Pivotal 团队提供的全新框架&#xff0c;其设计目的是用来 简化 Spring 应用的初始搭建以及开发过程。 Spring 程序缺点&#xff1a;依赖设置繁琐、配置繁琐 SpringBoot 程序优点&#xff1a;起步依赖&#xff08;简化依赖配置&#xff09;、自动配置&#x…

查看当前目录下文件所占用内存 du -sh

1. du -sh 查看当前目录下文件所占用内存 2.查看当前文件夹下&#xff0c;每个文件所占用内存 du -ah --max-depth1/

点云配准流程

迭代最近点算法&#xff08;Iterative CLosest Point简称ICP算法&#xff09; ICP算法对待拼接的2片点云&#xff0c;首先根据一定的准则确立对应点集P与Q&#xff0c;其中对应点对的个数&#xff0c;然后通过最小二乘法迭代计算最优的坐标变换&#xff0c;即旋转矩阵R和平移矢…

Soul CEO张璐团队优化治理平台安全生态,构建健康社交秩序

致力于构建真实、温暖、多元线上社交空间的Soul APP,在2023第二季度发布了全新的《Soul生态安全治理报告》。报告显示,Soul 主要以五大安全点位为阵地,开展专项安全生态治理,五大专项分别是反电信网络诈骗、引导社交礼仪规范、未成年保护、用户共治众裁和防治网暴骚扰。Soul CE…

红动大湾区!“红西凤”领衔西凤酒核心产品亮相秋糖

执笔 | 文 清 编辑 | 萧 萧 600亿元酒水消费规模的广东市场&#xff0c;再遇中国四大名酒之一的西凤酒&#xff0c;会碰撞出什么样的火花&#xff1f; 10月7日-11日&#xff0c;西凤酒携红西凤系列、西凤酒珍藏版、老绿瓶系列等全明星产品阵容&#xff0c;在深圳华侨城洲…

WindowsServer2019-部署与管理Active Directory域服务-01

文章目录 创建和配置域控制器1、创建域控制器步骤1&#xff1a;更名计算机步骤2&#xff1a;修改DC的IP地址步骤3&#xff1a;安装Active Directory域服务和DNS服务器角色步骤4&#xff1a;提升为域控制器 2、添加额外域控制器&#xff08;BDC&#xff09;步骤1&#xff1a;按照…