C++ | Date 日期类详解

目录

简介

日期类总代码  |  Date

类的定义 & 构造 & Print

类的定义

构造函数 & Print

比较类,如<、>、<=......

值加减类,如+、-、+=、-=......

加减类具体分类

判断某个月有多少天 GetMonthDay

日期类 + / +=(- / -=) 整数

日期类 - 日期类

日期类++ / --(前置后置)

流相关,如<<、>>(cout、cin)

结语


简介

日期类Date实现的本质就是  运算符重载  和  赋值运算符重载

我们要实现自定义类型像内置类型一样相加减,肯定会用到operator关键字+操作符

接下来我们要实现的分为三类:

  1. 比较类,如<、>、<=......
  2. 值加减类,如+、-、+=、-=......
  3. 流相关,如<<、>>(cout、cin)

日期类总代码  |  Date

如果有需要代码的同学,下方的链接是我上传到 gitee 里的代码

2024 - 5 - 3 - gitee - Date

类的定义 & 构造 & Print

我们会建三个文件:

  1. test.cpp
  2. Date.cpp
  3. Date.h

其中我们的Date.h是头文件,我们的函数声明与类的定义,以及头文件都被包含在头文件里面

另外,我们在正式开始开始讲解日期类之前,我们需要先将类给定义出来,然后将其的构造函数、析构函数、Print函数写好

类的定义

代码如下:

class Date
{
public:
	
private:
	int _year;
	int _month;
	int _day;
};

构造函数 & Print

我们现在写函数都需要现在类中声明一份,然后再到Date.cpp中去实现逻辑,最后到test.cpp中进行测试

Date.h 内部代码如下:

class Date
{
public:
    //构造函数声明
	Date(int year = 1, int month = 1, int day = 1);

	void Print();
private:
	int _year;
	int _month;
	int _day;
};

Date.cpp 内部逻辑实现:

Date::Date(int year, int month, int day)
	:_year(year)
	, _month(month)
	, _day(day)
{}

void Date::Print()
{
	cout << _year << " "
		<< _month << " "
		<< _day << endl;
}

由于我们分成了头文件与.cpp文件,所以我们在.cpp文件中实现逻辑之前我们得先Date::一下

不然我们就没法使用我们定义的类

比较类,如<、>、<=......

在开始之前,我得先介绍一个符号防止有同学没听说过:!

这个是逻辑取反:0 取反就是非 0,非 0 取反就是 0

对于这一类,我们的实现逻辑是这样的:

我们先实现<,然后再实现==

当我们将这两个实现了之后,我们就可以复用这两个,然后将其余所有比较类的函数全都表示出来

试想一下:我们实现了<和==,当我们要实现<=怎么办

那是不是同时满足<和==就算是<=

这是我们要实现>怎么办

当一个数不<=时,即<=取反( ! 符号)就是 >

闲话少叙,我们先来实现一下 小于<

bool Date::operator<(const Date& d)const
{
	if (_year < d._year)
		return true;
	else if (_year == d._year)
	{
		if (_month < d._month)
			return true;
		else if (_month == d._month)
		{
			if (_day < d._day)
				return true;
		}
	}
	return false;
}

注意看,我们在上文中实现的逻辑是:如果年小于,那就小于

如果年相等(大于的情况统一出判断之后返回false),那我们就看月,如果月小于,那就小于

如果月相等,那就看天,天小于,那就小于

如果上述条件都不符合,那就是大于或者等于,反正就是不小于

注:我们这里要的只是小于,如果等于或大于,那就不是小于

接着我们来实现一下 等于==

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

等于的实现逻辑相当简单,只有在我的年月日都相等的时候我的两个日期才想等

但凡有一个不相等,那就是不相等,全相等我们就直接返回一个 1,反之则是 0

接着就是很有意思的复用环节了,我们来实现一下 小于等于<=

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

你会看到,我们直接将自定义类型像内置类型一样进行了比较

但是这些比较的符号都是我们刚刚才实现过的:<、==

当两个日期既小于又等于时,那么这两个日期就是小于等于

趁热打铁,我们再一鼓作气将 >、>=、!=给一起实现了

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

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

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

我们能看到,大于就是小于等于取反

大于等于就是小于取反

不等于就是等于取反

值加减类,如+、-、+=、-=......

加减类具体分类

加减类里面其实还分了三类

  1. 日期类 + / +=(- / -=) 整数(某个日期的多少天之后)
  2. 日期类 - 日期类(宝宝,今天离我们刚开始在一起已经过了多少天了呀)
  3. 日期类++ / --(前置后置) 

判断某个月有多少天 GetMonthDay

在正式开始讲之前,我们为了防止后序的逻辑太乱,所以我们就单独将判断某个月有多少天的逻辑拿出来单独实现

而这个函数我们可以在类里面实现,这是为了类的包装,增加安全性、

当然如果你非要将其定义在全局也不是不可以,随你喜欢,出事了与我无瓜

接下来我们来讲一讲判断某个月有多少天的逻辑

由于一年有12个月,如果一个月一个月地返回的话,那就太挫了

所以我们可以创建一个数组,返回之时我们就可以把月当下标返回了

int MonthDayArray[13] =
{ -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

可以看到,我们创建了一个13个数的数组,因为第一个的下表为0,我们要的效果是1月对应下标1

但是平年和闰年的判断关乎了二月的大小,所以我们不妨假设二月是28天

接着我们在下面判断今年是不是闰年且   要返回的月份是不是2月,如果不是二月,那我们判不判断闰年其实没意义

所以,如果月为2月,如果传过来的年判断为闰年,我们直接返回29即可

如果不是闰年或者根本就不是二月,那我们就返回每个月对应的对应数组下标中的值即可

代码如下:

int GetMonthDay(int year, int month)
{
	assert(month < 13 && month > 0);
	int MonthDayArray[13] =
	{ -1, 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 MonthDayArray[month];
}

日期类 + / +=(- / -=) 整数

首先我们先来想一个问题:+和+=之间有什么不同

+是将值传过去,自身并不会改变,比如 int i = n + m; 其中 n 和 m 并没有改变

而 += 是自身的值会改变

所以我们面对这两类函数时,返回值也不一样,因为面对自身不改变的情况,我们只能创建一个临时变量,但是临时变量出了函数会销毁,所以我们的返回值不能为引用,需要让其调用拷贝构造函数,所以返回值类型为 Date

但是如果是对象自身要改变的情况,那我们就无需创建临时变量,直接在原对象的基础上进行改变即可,最后直接返回*this,所以返回值的类型需为引用,为了防止调用不必要的拷贝构造影响效率,所以参数的返回值类型为 Date&

我们先来实现一下 +=

+= 的逻辑如下:

我们先将 _day 与 day 直接相加,然后我们再对 _day 进行减小,每次减一个月的天数

我们while循环内的逻辑就是,当我的 _day 减小到比 GetMonthDay 函数返回的天数要大时,就证明我们的天数还需要再减

就好比我的月本来是 24,我想知道 100 天后是那一天,我就先 24 + 100 = 124

但是124肯定不止一个月的量,所以我们需要减

假设现在是3月,我就124 - 31 = 93,然后就来到了 4 月,但是还是有多,我就继续减,现在是 4 月就减 30,93 - 30 = 63......

直到 _day 是正常的,循环终止

我们每减一次日期,我们的月就要++一次

当我们的月为13时,我们就将13手动置为1,随后年++

Date& Date::operator+=(int day)
{
	_day += day;

	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);
		++_month;
		if (_month == 13)
		{
			_month = 1;
			++_year;
		}
	}
	return *this;
}

接着我们来实现一下 +

+其实就可以直接复用+=

我们可以直接创建一个和*this一摸一样的Date类型对象tmp

我们只需要对tmp进行改变(+=)最后返回即可

代码如下:

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

接着是 -= 的实现

-= 的逻辑和 += 很类似,只不过我们现在是直接 _day - day

如此一来,我们的 _day 就为负数,我们就需要不断对其进行加的操作,并在此过程中注意月的--和年的--

但是有一个点需要注意的是,如果调用这个函数的人,要-=却传了一个负数过来,那就单独对其进行判断

如果传过来的是负数,那我们就将其 += 上负的参数即可

代码如下:

Date& Date::operator-=(int day)
{
	if (day < 0)
		return *this += - day;

	_day -= day;

	while (_day <= 0)
	{
		_day += GetMonthDay(_year, _month);
		--_month;
		if (_month == 0)
		{
			_month = 12;
			--_year;
		}
	}
	return *this;
}

最后是 - 的实现

类似的,我们的减就是实例化一个和 *this 一摸一样的临时对象 tmp(拷贝构造),然后对其进行 -= 操作,最后返回 tmp 即可

代码如下:

Date Date::operator-(int day)const
{
	Date tmp = *this;
	tmp -= day;
	return tmp;
}

日期类 - 日期类

可能有人会疑惑,为什么只有日期类的-,而没有+

这是因为日期类的+是没有意义的,试想,2024年1月13号 + 2024年3月31号有什么意义?

而 - 之所以有意义是因为,如果未来有一天你的对象问你:宝,这是我们在一起的第几天啊?

也就是两个日期之间相差几天,这个是有意义的

而我们要实现这个的逻辑也较为简单:

我们只需要将两个日期分为大和小

我们找出小的那一个,不断让其+=1,然后再额外设置一个整形变量,小的那个日期类每+=1一次,整型变量就 ++ 1次

当小的那个日期和大的那个日期相等的时候,我们创建出来的那个整型变量的值就是两个日期之间的差值

当然,为了防止两个日期之间的差值为负数的情况,我们应该先将this指针指向的设置为max,另一个参数指向的为min,如果此时发现设置的max比min要小,那我们就将两者进行交换,随后设置一个变量flag,如果存在max小于min而后两者需要交换的情况,那我们就将flag赋值为-1,否则flag为1

最后返回的结果是两个日期之间的差值*flag

代码如下:

int Date::operator-(const Date& d)
{
	Date max = *this;
	Date min = d;
	int flag = 1;
	int count = 0;
	if (*this < d)
	{
		max = d;
		min = *this;
		flag = -1;
	}
	while (max != min)
	{
		min += 1;
		count++;
	}
	return count * flag;
}

日期类++ / --(前置后置)

其实我们++或--的逻辑在我们将+=和-=实现完了之后都变得非常简单

我们++本质将就是+=1,那我们之间将日期类+=1即可实现++

直接将日期类-=1即可得到--

需要详细讲解的是前置与后置

我们前置与后置唯一的区别就在于,一个是先++后使用,一个是先使用后++

但是我们在写操作符名称的时候,都只能写operator++,所以我们无法分辨哪个是前置哪个是后置

本贾尼博士也发现了这个漏洞,所以就规定说,在传参数的括号中加上一个int的就是后置++

而这个int并不是说要传值的意思,里面传多少都没用,可以理解为就是对编译器的一个提醒,告诉编译器我现在的这个++是后置++

而我们前置与后置的函数返回值类型也是不一样的

前置是直接对*this指向的内容进行修改,修改完后直接返回*this即可,而*this并不是临时变量,出了函数并不会被销毁,所以我们函数的返回类型是引用,这样可以防止多调用拷贝构造影响效率,Date&

后置是需要在函数内部实例化一个临时变量tmp,而我们直接对*this进行修改,最后将tmp返回,因为我们实现的是后置++,*this指向的内容需要更改,但是我们需要返回的是一个更改之前的值,所以我们需要备一份。但是对象tmp是临时的,出了函数的作用域就会被销毁,所以我们只能任其调用拷贝构造,所以返回类型不能为引用Date

综上,++ / --(前置 / 后置)代码如下:

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

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

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

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

流相关,如<<、>>(cout、cin)

我们在C语言中曾学到了printf和scanf

我们都知道其用法,就是先指定类型,接着我们再将要打印的变量放上去

如果只是打印内置类型还好,但如果是打印自定义类型呢?我们没办法用printf打印自定义类型

本贾尼博士之所以整了一个cout、cin(流插入流提取),就是因为想像打印内置类型一样打印自定义类型的,并且cout可以自动判断要打印变量的类型

我们来看一张图:

如上我们可以看到,cout 和 cin 是两个实例化出来的全局对象,类的类型分别是 ostream、istream

而 ostream、istream 又被包在iostream里面

而我们如果想要实现可以像内置类型一样打印自定义类型的话,我们只需要自己实现一下operator<< 和 operator>> 即可

我们先不考虑连续打印的问题,返回值先设置为void

而我们的参数就传一个ostream&类型的对象即可,剩下还有一个this指针(这里埋一个坑)

代码如下:

void Date::operator<<(ostream& out)
{
	out << _year << " " << _month << " " << _day << endl;
}

但是当我们想要调用的时候,却会发现调用不了

Date s1(2024, 1, 13);
cout<<s1;

你会发现调用不了,这是因为我们在调用的时候,要遵循的顺序是参数的顺序

看我们函数内实现的逻辑,我们的第一个参数是this指针,随后才是ostream

这就意味着如果按照上面写的函数的话,我们就需要将调用的顺序改一下我们才能调用成功

Date s1(2024, 1, 13);
s1<<cout;

如果还不理解的话,我们来显示调用一下我们的函数相信你就能看得懂了

s1.operator<<(cout)

综上,我们如果这么写的话与我们日常的使用逻辑相悖,所以我们需要做出相应的调整

但是this指针已经将第一个参数的位置给牢牢地占住了,我们没有办法做更改

所以我们需要将这个函数变为全局的

当这个函数编程全局的的时候,我们就能够自己定义参数的位置了

void operator<<(ostream& out, const Date& d)

但是如上我们就=还是不能正常调用

这是因为当我们将这个函数变为全局函数的时候,这个函数就无法调用类里面的私有变量

为此,我们需要使用友元的方式进行解决

我们在这里先简单提一下友元的概念,具体的知识我们放到下一篇博客类和对象下中去讲

友元,就是说:我是你的朋友,所以你的东西就是我的东西,但是只是你把我当朋友,我还没有把你当朋友,所以你的东西我能用,但我的东西你不能用

要定义成友元也比较简单,我们只需将函数的声明在类中任意位置放一份,并在最前面加上一个friend即可,如下:

friend ostream& operator<<(ostream& out, const Date& d);
friend istream& operator>>(istream& in, Date& d);

.h文件全:

class Date
{
	friend ostream& operator<<(ostream& out, const Date& d);
	friend istream& operator>>(istream& in, Date& d);

public:
	Date(int year = 1, int month = 1, int day = 1);

	void Print();

	int GetMonthDay(int year, int month)
	{
		assert(month < 13 && month > 0);
		int MonthDayArray[13] =
		{ -1, 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 MonthDayArray[month];
	}

	bool operator<(const Date& d)const;
	bool operator>(const Date& d)const;
	bool operator<=(const Date& d)const;
	bool operator>=(const Date& d)const;
	bool operator==(const Date& d)const;
	bool operator!=(const Date& d)const;

	Date& operator+=(int day);//*this要变,故不加const
	Date operator+(int day)const;
	Date& operator-=(int day);
	Date operator-(int day)const;

	int operator-(const Date& d);

	Date& operator--();
	Date operator--(int);
	Date& operator++();
	Date operator++(int);

	//日期类无需析构函数,编译器默认生成的就够用
private:
	int _year;
	int _month;
	int _day;
};

ostream& operator<<(ostream& out, const Date& d);
istream& operator>>(istream& in, Date& d);

所以我们的<<就变成了:

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

但是,如果我们遇到需要连续打印的情况,我们写的这个函数就不够用了,因为没有返回值

但是如果我们想要支持连续打印的话,我们需要将out传回去

所以,最终版本如下:

ostream& operator<<(ostream& out, const Date& d)
{
	out << d._year << " " << d._month << " " << d._day << endl;
	return out;
}

接着我们来看一下   >>

这个也是一样的,我们的istream是一个类,我们同样将其设置为全局函数,最后通过友元的方式令其能够访问到私有变量,而为了支持连续赋值,所以我们同样需要一个返回值,返回值的类型就是istream&

代码如下:

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

结语

到这里我们的日期类就结束了

如果你觉得这篇博客对你有帮助的话,希望各位能够多多支持!!

(比心)

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

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

相关文章

场景文本检测识别学习 day08(无监督的Loss Function、代理任务)

无监督的Loss Function&#xff08;无监督的目标函数&#xff09; 根据有无标签&#xff0c;可以将模型的学习方法分为&#xff1a;无监督、有监督两种。而自监督是无监督的一种无监督的目标函数可以分为以下几种&#xff1a; 生成式网络的做法&#xff0c;衡量模型的输出和固…

protobuf在配置文件管理上的应用

TextFormat::ParseFromString 是 Google Protocol Buffers&#xff08;通常简称为 Protobuf&#xff09;库中的一个函数&#xff0c;用于从文本格式解析消息。Protobuf 是一种用于序列化结构化数据的库&#xff0c;它允许你定义数据的结构&#xff0c;然后自动生成源代码来处理…

【实用推荐】7个靠谱赚钱软件,宅家也能轻松赚钱!

在数字化浪潮下&#xff0c;如何在家轻松赚取收益成为许多人关注的焦点。软件市场的蓬勃发展为我们提供了多种选择&#xff0c;但面对琳琅满目的赚钱应用&#xff0c;许多人感到无从下手&#xff0c;担心选择不当。本文将为您揭示这些软件背后的奥秘&#xff0c;助您找到最适合…

【副本向】高等级副本全流程开发

副本的创建 1.从配置表通过副本ID获取此副本参数 Tab_CopyScene rCopyScene TableManager.GetCopySceneByID(m_CopySceneID);if (rCopyScene ! null){//只要配置了组队的Rule&#xff0c;就是组队模式&#xff0c;否则就是单人模式bool bSolo true;for (int n 0; n < rCo…

禅道项目管理系统 身份验证漏洞分析QVD-2024-15263

前言 最近不怎么更新了&#xff01;向小伙伴说明下 我不是什么组织 更不什么经销号&#xff08;尽管csdn有很多经销广告号&#xff09; 一确实是下岗了&#xff01;忙着为找工作而发愁。简历都投出去如同石沉大海能不愁吗!.哎...... 二是忙着论文及材料的事...…

观察者模式实战:解密最热门的设计模式之一

文章目录 前言一、什么是观察者模式二、Java实现观察者模式2.1 观察者接口2.2 具体观察者2.3 基础发布者2.4 具体发布者2.5 消息发送 三、Spring实现观察者模式3.1 定义事件类3.2 具体观察者3.3 具体发布者3.4 消息发送 总结 前言 随着系统的复杂度变高&#xff0c;我们就会采…

电商独立站最重要的功能设置:多语言转换和代运系统搭建

什么是独立站&#xff1f; 多语言模式切换 1 搭建电商独立站在我看来最简单的理解&#xff0c;就是独立的网站。 如果你在跨境圈子呆了一段时间&#xff0c;独立站是一个避不开且火热的一个词&#xff0c;并且也是所有的B2B、B2C商家都在运营和布局的市场。 独立站的优势有哪…

AI视频教程下载:零代码创建AI智能体、AI Agents和ChatGPT的Gpts

这门课程专注于提示工程的掌握&#xff0c;教你以精确的方式引导GPT&#xff0c;利用它们的生成能力产生卓越的AI驱动结果。一步一步地&#xff0c;你将学会创建多样化的GPT军团——每个都设计来满足特定的专业需求。 从提供个性化职业变更指导的职业教练AI&#xff0c;到以惊…

精准测试-Vue前端调用链影响变更分析之一

Vue前端调用链影响变更分析之一 一、背景二、工具调研1、 工具介绍&#xff1a;2、工具使用 三、工具落地集成方案&#xff08;待后续补充&#xff09;变更影响较为简单的实现变更影响较为复杂的实现1、全局关系数据库的构建2、变更影响的简单实现3、变更影响的复杂实现 一、背…

【LinuxC语言】系统日志

文章目录 前言一、系统日志的介绍二、向系统日志写入日志信息三、示例代码总结 前言 在Linux系统中&#xff0c;系统日志对于监控和排查系统问题至关重要。它记录了系统的运行状态、各种事件和错误信息&#xff0c;帮助系统管理员和开发人员追踪问题、进行故障排除以及优化系统…

(Microsoft SQL Server,错误: 233)

错误信息: A connection was successfully established with the server, but then an error occurred during the pre-login handshake. (provider: Shared Memory Provider, error: 0 - 管道的另一端上无任何进程。) (Microsoft SQL Server&#xff0c;错误: 233) 原因&…

《十三》QT绘图原理双缓冲机制

一、原理与设计 所谓双缓冲机制&#xff0c;是指在绘制控件时&#xff0c;首先将要绘制的内容绘制在一个图片中&#xff0c;再将图片一次性地绘制到控件上。在早期的 Qt 版本中&#xff0c;若直接在控件上进行绘制工作&#xff0c;则在控件重绘时会产生闪烁地现象&#xff0c;控…

零基础学习数据库SQL语句之定义数据库对象的DDL语句

DDL语句 DDL Date Definition Language 数据定义语言&#xff0c;用来定义数据库对象&#xff08;数据库&#xff0c;表&#xff0c;字段&#xff09; 基本操作 数据库操作 查询所有数据库 SHOW DATEBASES查询当前数据库 SELECT DATEBASE() 创建 CREATE DATEBASE [IF …

利用大语言模型(KIMI)构建智能产品的控制信息模型

数字化的核心是数字化建模&#xff0c;为一个事物构建数字模型是一项十分复杂的工作。不同的应用场景&#xff0c;对事物的关注重点的不同的。例如&#xff0c;对于一个智能传感器而言&#xff0c;从商业的角度看&#xff0c;产品的信息模型中应该包括产品的类型&#xff0c;名…

Mysql的关联查询以及语句

一、mysql的连接查询 1、等值连接 这里是三张表的等值连接 select rp.role_id,rp.permission_id from role_permission rp, role r, permission p where rp.role_idr.id and rp.permission_idp.id 2、内连接&#xff1a; 角色&#xff1a;系统管理员 是否拥有权限&#xf…

DHCPv4_CLIENT_ALLOCATING_03: 发送DHCPREQUEST - 必须包含‘服务器标识符‘

测试目的&#xff1a; 验证客户端发送的DHCPREQUEST消息中是否包含“服务器标识符”选项&#xff0c;以指示它选择的服务器。 描述&#xff1a; 本测试用例旨在确保DHCP客户端在广播DHCPREQUEST消息时&#xff0c;必须包含“服务器标识符”选项。该选项用于指明客户端选择了…

2024-5-1我把QQ群聊天记录分析工具重写了一下

【下载地址】 https://www.lanzoub.com/b00rn0g47e 密码:9hww 【项目背景】 2020年我用Tkinter写过一个QQ群聊天记录分析的工具exe&#xff0c;后续也写过一个纯JS前端的版本&#xff0c;前阵子有个用户反馈不能用了&#xff0c;顺便看能不能加入一个分析关键词的功能&…

第76天:WAF攻防-信息收集识别被动探针代理池仿指纹白名单

目录 基础知识 案例一: 信息收集-被动扫描-黑暗引擎&三方接口 案例二: 信息收集-目录扫描-Python 代理加载脚本 案例三: 信息收集-爬虫扫描-Awvs&Xray&Goby内置 基础知识 什么是 WAF &#xff1f; Web Application Firewall &#xff08; web 应用防火墙&am…

jvm垃圾回收机制介绍

JVM&#xff08;Java虚拟机&#xff09;是Java程序的运行环境&#xff0c;它负责执行字节码文件。JVM的工作原理主要包括以下几个部分&#xff1a;类加载器、执行引擎、垃圾收集器和内存管理。类加载器负责加载字节码文件并将其转换成Java平台上的机器码&#xff0c;执行引擎负…

三维图形学知识分享---求平面与模型相交线

在CGAL&#xff08;Computational Geometry Algorithms Library&#xff09;中&#xff0c;Polygon_mesh_processing模块提供了用于处理多边形网格数据结构的功能。其中&#xff0c;surface_intersection函数是用来计算模型的表面相交线的工具。 CGAL_Mesh mesh_orcl;std::vect…