【是C++,不是C艹】 类与对象 | 默认成员函数 | 构造函数 | 析构函数

news2024/12/24 3:06:51

💞💞欢迎来到 Claffic 的博客💞💞

 👉 专栏:《是C++,不是C艹》👈

前言:

在完成类与对象的认识后,我们接着学习类与对象的第二部分:默认成员函数,它包括构造函数,析构函数,拷贝构造,赋值重载,普通对象取地址和const对象取地址重载,放心,这一期不会都讲给你的,让我们来慢慢研究构造函数和析构函数:

注:

你最好是学完了C语言,并学过一些初阶的数据结构。


(没有目录) ヽ( ̄ω ̄( ̄ω ̄〃)ゝ 

Part1:默认成员函数

上一次我们提到了空类,里面没有成员,编译器给了它一个字节表示它存在,

class Date {};

❓那空类中真的什么也没有吗?

并不是的,编译器可是让你省心的存在:

类为空时,编译器会自动生成6个默认成员函数

❓生成是会生成,那它们有什么用呢?

🌰有个例子:

上次我们提到了 Stack 的实现,其中有初始化函数 StackInit 和销毁函数 StackDestroy 

现在告诉你个好事:构造函数可以代替 StackInit ,析构函数可以代替 StackDestroy 。 

📢重点:它们都是编译器自动生成的,也就是说 像这种初始化函数和销毁函数不需要自己造了

当然不止这些,还有拷贝赋值和取地址重载等,大大方便了我们。

那么接下来,就由“构造函数”讲起:

Part2:构造函数

1.一个引子

🪄为了更方便地讲解,我们先定义一个 Date 类:

#include<iostream>
using namespace std;

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

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

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

int main()
{
	Date d1;
	d1.SetDate(2023, 6, 1);
	d1.Print();

	Date d2;
	d2.SetDate(2023, 6, 4);
	d2.Print();

	return 0;
}

对于 Date 类来说,我每次要初始化设置信息,就要调用一次 SetDate 函数,那岂不是很烦?

❓那有没有一种办法,自动将我要传递的数值传递进去呢? 

❗还真有,那就是构造函数,让我们有请构造函数登场!!!

2.构造函数的概念

构造函数 是一个 特殊的成员函数,名字与类名相同 ,创建类类型对象时由编译器自动调用

能保证每个数据成员都有一个合适的初始值,并且在对象整个生命周期内只调用一次 

🗡️构造函数的意义在于初始化对象,而不是给对象开辟空间(虽然名字叫做构造)

3.构造函数的特性

📝构造函数是特殊的成员函数,其特性如下: 

① 函数名与类名相同;

② 没有返回值;

③ 构造函数可以重载;

④ 对象实例化时编译器自动调用对应的构造函数:

如上方代码中的 Date d1

构造函数就在这个时候被调用了

👀让我们康康它具体是怎么使用的:

#include<iostream>
using namespace std;

class Date
{
public:
	Date() // 无参构造函数
	{
		_year = 1;
		_month = 0;
		_day = 0;
	}

	Date(int year, int month, int day) // 带参构造函数
	{
		_year = year;
		_month = month;
		_day = day;
	}

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

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

int main()
{
	Date d1;	// 调用无参构造函数
	d1.Print();

	Date d2(2023, 6, 4); // 调用带参构造函数
	d2.Print();

	return 0;
}

👁️‍🗨️输出结果:

🪄不给参数就调用无参构造,给参数就调用带参构造

你以为你会了?其实有很多需要注意的地方:

🚨注意:

构造函数是特殊的函数,不是普通的成员函数,所以不可以这样调用

#include<iostream>
using namespace std;

class Date
{
public:
	Date()
	{
		_year = 1;
		_month = 0;
		_day = 0;
	}

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

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

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

int main()
{
	Date d1;	
	d1.Date;    // 不可以这样调用
	d1.Print();

	return 0;
}

👁️‍🗨️输出结果:

无参构造对象,对象后面不用跟括号,否则就成了函数的声明

#include<iostream>
using namespace std;

class Date
{
public:
	Date(int year = 1, int month = 0, int day = 0)
	{
		_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, 6, 5); // 带参就这样,括号加参数
	d1.Print();

	Date d2();  // 调用不带参构造函数,不要加括号
	d2.Print(); // 实际上这个类没有创建出来

	return 0;
}

报错: 

 

带参构造,该传递多少参数就传递多少参数

🚨如上三点要注意!

4.默认构造函数

我们聊完了构造函数,就要说说默认构造函数了:

如果你没有在类中定义构造函数(类中未显式定义),那么C++编译器就会自动生成一个无参的默认构造函数

#include<iostream>
using namespace std;

class Date
{
public:
	// 没有显式定义构造函数
	/*Date(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}*/

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

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

int main()
{
	Date d1;    // 调用默认构造函数
	d1.Print();

	return 0;
}

👁️‍🗨️输出结果:

🪄没有定义构造函数,也会成功创建对象,只不过用随机值来进行初始化

❓你是否和我有着同样的困惑:既然构造函数是用来初始化的,调用默认构造函数之后,确实是把类的成员参数初始化了,but 是用随机值初始化的,有一种没有初始化的赶脚... ... 🫠🫠🫠

默认构造函数没卵用吗?

这里我不说,等到后面再解答(哎呦,不就是想要骗你把文章读完嘛~)(狗头

继续回到默认构造函数:

无参构造函数、全缺省构造函数都被称为默认构造函数。

并且默认构造函数只能有一个!

class Date
{
public:
	 // 全缺省的默认构造函数
	Date(int year = 2023, int month = 6, int day = 5)
	{
		_year = year;
		_month = month;
		_day = day;
	}

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

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

🚨注意:

① 无参构造函数、全缺省构造函数、什么没写时编译器默认生成的构造函数,可以认为是默认构造函数(并不只有编译器默认生成的构造函数才叫做默认构造函数

② 无参构造和全缺省构造同时存在时会引发歧义:

#include<iostream>
using namespace std;

class Date
{
public:
	// 无参的默认构造函数
	Date()
	{
		_year = 2023;
		_month = 6;
		_day = 5;
	}

	 // 全缺省的默认构造函数
	Date(int year = 2023, int month = 6, int day = 5)
	{
		_year = year;
		_month = month;
		_day = day;
	}

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

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

int main()
{
	Date d1; // 这里报错
	d1.Print();

	return 0;
}

👁️‍🗨️输出结果:(报错)

🪄存在两个默认构造函数:无参的和全缺省的,但默认构造函数只能有一个,当类 d1 创建好后,编译器不知道用哪个构造函数来初始化。

  图源:柠檬叶子C

这种全缺省/半缺省的格外好用:

#include<iostream>
using namespace std;

class Date
{
public:
	// 全缺省的默认构造函数
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}

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

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

int main()
{
	Date d1; 
	d1.Print();

	Date d2(2023, 7, 14);
	d2.Print();

	Date d3(2023, 7);
	d3.Print();

	Date d4(2023);
	d4.Print();

	return 0;
}

👁️‍🗨️输出结果: 

5.进一步探讨构造函数

这一部分主要解决上面留下的一个疑问:

如果你没有在类中定义构造函数(类中未显式定义),那么C++编译器就会自动生成一个无参的默认构造函数

#include<iostream>
using namespace std;

class Date
{
public:
	// 没有显式定义构造函数
	/*Date(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}*/

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

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

int main()
{
	Date d1;    // 调用默认构造函数
	d1.Print();

	return 0;
}

👁️‍🗨️输出结果:

🪄没有定义构造函数,也会成功创建对象,只不过用随机值来进行初始化

❓你是否和我有着同样的困惑:既然构造函数是用来初始化的,调用默认构造函数之后,确实是把类的成员参数初始化了,but 是用随机值初始化的,有一种没有初始化的赶脚... ... 🫠🫠🫠

默认构造函数没卵用吗?

🪄解答:

C++把类型分成内置类型(基本类型)和自定义类型

内置类型:语言本身提供的数据类型,如 int / char / float

自定义类型:我们使用 class / struct / union 等自己定义的类型。

我们一起来看看下面的程序: 

#include<iostream>
using namespace std;

class Time
{
public:
	Time()
	{
		cout << "Time()被调用" << endl; // 调用就会打印
		_hour = 0;
		_minute = 0;
		_second = 0;
	}
private:
	int _hour;
	int _minute;
	int _second;
};

class Date
{
// 这里没有显式定义构造函数
private:
	// 基本类型(内置类型)
	int _year;
	int _month;
	int _day;
	// 自定义类型
	Time _t;
};
int main()
{
	Date d;

	return 0;
}

👁️‍🗨️输出结果: 

🗡️我们可以看出,编译器生成的 Date 默认构造函数会对自定义 Time 类型成员 _t 调用它的默认成员函数。

编译器默认生成构造函数:

对于内置类型的成员变量,会用随机值进行“处理”。

对于自定义类型的成员变量,会去调用它的默认构造函数(不用参数就可以调的)初始化。

❓随机值果然很挫,有没有一种办法,即能用到编译器默认生成的构造函数,又能使内置类型不是随机值?

这里提供一种方法:就是在定义内置类型的时候就给一个初始值(C++11 内置类型成员变量在类中声明时可以给默认值

#include<iostream>
using namespace std;

class Time
{
public:
	Time()
	{
		cout << "Time()被调用" << endl; // 调用就会打印
		_hour = 0;
		_minute = 0;
		_second = 0;
	}
private:
	int _hour;
	int _minute;
	int _second;
};

class Date
{
public:
	// 这里没显式构造函数
	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	// 基本类型(内置类型) 给初始值
	int _year = 1;
	int _month = 1;
	int _day = 1;
	// 自定义类型
	Time _t;
};
int main()
{
	Date d;
	d.Print();

	return 0;
}

👁️‍🗨️输出结果:

是不是爽歪歪? 

Part3:析构函数

1.一个引子

❓在前面构造函数的学习之后,我们知道了一个对象是怎么来的,那么一个对象是怎么没的呢?

构造函数的使命是初始化,那么谁来做清理工作?

❗那就是 -- 析构函数

2.析构函数的概念

对象在销毁时调用析构函数,完成对象中资源的清理工作

🚨注意:析构函数不是完成对象本身的销毁,局部对象销毁工作是由编译器完成的

3.析构函数的特性

📝析构函数也是特殊的成员函数,其特征如下:

① 析构函数名是在类名前加上字符 ~

② 无返回类型,也无参数

③ 一个类只能有一个析构函数,若无显式定义,系统会自动生成默认的析构函数。

注意:析构函数不能重载

④ 对象的声明周期结束时,C++编译系统自动调用析构函数:

 为了演示自动调用,就让析构函数被调用时 “仙逝” 一波 ~ 

#include <iostream>
using namespace std;

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

    ~Date() 
    {
        cout << "~Date() 仙逝~ " << endl;  // 测试一波
    }

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

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

int main()
{
    Date d1;
    Date d2(2023, 6, 5);

    return 0;
}

👁️‍🗨️输出结果:

🪄因为创建了两个 Dated1 , d2 ,所以都会自动销毁

析构函数的魅力不止,为了更好的演示,下面就采用 Stack :

之前实现 Stack ,最后需要 StackDestroy 来清理栈中的数据,

现在可以让析构函数来干这个活,泰爽辣:

#include <iostream>
#include <cstdlib>
using namespace std;

typedef int DataType;
class Stack
{
public:
	// 构造函数 默认容量为4
	Stack(size_t capacity = 4)
	{
		_array = (DataType*)malloc(sizeof(DataType) * capacity);
		if (NULL == _array)
		{
			perror("malloc failed");
			return;
		}
		_capacity = capacity;
		_size = 0;
	}
	void Push(DataType data)
	{
		// CheckCapacity();
		_array[_size] = data;
		_size++;
	}
	// 析构函数 清理开辟的空间,防止内存泄露
	~Stack()
	{
		if (_array)
		{
			free(_array);
			_array = NULL;
			_capacity = 0;
			_size = 0;
		}
	}
private:
	DataType* _array;
	int _capacity;
	int _size;
};

void TestStack()
{
	Stack s1; // 默认容量为4
	Stack s2(10); // 设置初始容量为10
}

🪄缺省了一个初始容量,也可以自己定义   另外不需要手动调用析构函数,都交给编译器。

继续回到析构函数的特性:

⑤ 编译器默认生成的析构函数,对自定义类型成员调用它的析构函数:

这一点与构造函数相同,下面来测试

#include <iostream>
using namespace std;

class Time
{
public:
	~Time()
	{
		cout << "~Time() 仙逝~" << endl;
	}
private:
	int _hour;
	int _minute;
	int _second;
};
class Date
{
private:
	// 基本类型(内置类型)
	int _year = 1970;
	int _month = 1;
	int _day = 1;
	// 自定义类型
	Time _t;
};
int main()
{
	Date d;
	return 0;
}

👁️‍🗨️输出结果:

❓明明没有创建 Time 类的对象,为什么最后会调用 Time 类的析构函数?

🪄解释:

编译器默认生成了 Date 类的析构函数,Date 类中含有自定义类型 Time ,于是 Date 类的析构函数调用了 Time 类的析构函数,做到当 Date 对象销毁时,保证其内部每个对象都正确销毁。

🚨注意:创建哪个类的对象则调用该类的析构函数,销毁哪个类的对象则调用该类的析构函数

⑥ 如果类中没有申请资源时,析构函数可以不写,直接使用编译器生成的默认析构函数,如 Date      类;

     如果有资源申请,一定要写,否则会造成内存泄漏,如 Stack 类,其中含有动态内存申请,所       以一定要写。

4.进一步探讨析构函数

我们知道了如果你不写析构函数,编译器会自动生成一个默认析构函数,这个默认析构函数会做些什么呢?

📝先来串联一下过来的知识:

如果你不写构造函数,编译器会自动生成,这个自动生成的 默认构造函数

• "内置类型" 成员变量:不会做初始化处理
• "自定义类型" 成员变量:会调用它的默认构造函数初始化

对应的,析构函数也是这样: 

如果你不写析构函数,编译器会自动生成,这个自动生成的 默认析构函数

• "内置类型" 的成员变量:不作处理,也不需要处理,系统将其内存回收
• "自定义类型" 的成员变量:会调用它对应的析构函数

就如特性⑤所提到的:

编译器默认生成的析构函数,对自定义类型成员调用它的析构函数:

#include <iostream>
using namespace std;

class Time
{
public:
	~Time()
	{
		cout << "~Time() 仙逝~" << endl;
	}
private:
	int _hour;
	int _minute;
	int _second;
};
class Date
{
private:
	// 基本类型(内置类型)
	int _year = 1970;
	int _month = 1;
	int _day = 1;
	// 自定义类型
	Time _t;
};
int main()
{
	Date d;
	return 0;
}

👁️‍🗨️输出结果:


总结: 

这篇带大家认识了6个默认成员函数,再给大家详细讲解了构造函数和析构函数,思维不要停留在C语言阶段啦,C++编译器可以帮你做很多事情的!

码文不易 

如果你觉得这篇文章还不错并且对你有帮助,不妨支持一波哦  💗💗💗

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

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

相关文章

基于深度学习的高精度野外烟雾检测识别系统(PyTorch+Pyside6+YOLOv5模型)

摘要&#xff1a;基于深度学习的高精度野外烟雾检测识别系统可用于日常生活中检测与定位野外烟雾目标&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的野外烟雾目标检测识别&#xff0c;另外支持结果可视化与图片或视频检测结果的导出。本系统采用YOLOv5目标检测…

FastReport Business Graphics .NET crack

FastReport Business Graphics .NET crack FastReport Business Graphics.NET允许您可视化层次结构信息并创建业务图以进行进一步分析。FastCube.NET允许您连接到任何应用程序。包括树图、太阳爆发图和冰柱图。 FastReport Business Graphics库允许您可视化分层数据&#xff0c…

虚幻ue镜头试拍录制器用法 5.2录制角色的的操作并按特定键播放探索

在窗口-开启镜头试拍录制器 image.png 添加源为Player image.png 这个时候录制的圆形按钮警告已经消失, 切换游戏模式为模拟 image.png 运行后点击手柄切换 进行实际的控制 image.png 点击录制之后,在cinema 的take文件夹找到文件 把文件拖动到关卡,然后 创建蓝图按L键 然后创建…

(CVPR-2023)通过有效的时空特征融合进行多模态步态识别

通过有效的时空特征融合进行多模态步态识别 paper题目&#xff1a;Multi-modal Gait Recognition via Effective Spatial-Temporal Feature Fusion paper是北航发表在CVPR 2023的工作 paper地址 Abstract 步态识别是一种生物识别技术&#xff0c;通过步行模式识别人。基于剪影…

指针 --- 进阶

先看目录&#xff0c;看你知道多少 目录 1.字符指针 2.指针数组 3.数组指针 4.数组传参和指针传参 5.函数指针 6.函数指针数组 7.指向函数指针数组的指针 8.回调函数 什么是指针&#xff0c;我们在之前的《指针》章节已经接触过了&#xff0c;我们知道了指针的概念: 1…

软件测试——功能测试,使用Java,IDEA,Selenium进行web自动化测试

视频地址&#xff1a;03-web元素定位ID_哔哩哔哩_bilibili p1.下载jdk,maven,idea p2.配置java-selenium环境正式开始&#xff1a; &#xff08;1&#xff09;创建代码&#xff1a; &#xff08;2&#xff09;第一次运行会报错&#xff1a;要下载东西 &#xff08;3&…

如何设计一个过压保护电路

有时候在电源输入处我们希望当电源的输入电压超过允许的最大值后电源与后级电路就自动断开&#xff0c;防止输入电压过高而损坏后级电路。 具有这种功能的电路叫做过压保护电路&#xff0c;英文简称叫OVP。 现在大家看到的就是一个典型的过压保护电压电路&#xff0c;主要包含…

(一)springboot实战——为什么是springboot?

前言 为什么是springboot&#xff1f;江湖夜雨&#xff0c;传说依旧&#xff0c;不懂springboot一技之长&#xff0c;如何混迹java圈&#xff0c;本节内容我们介绍一下spring的一些基本特性。尤其是springboot3的基本特性&#xff0c;使得我们更好的理解springboot3。 正文 …

【vue3】07-vue组件之间的通信-父子互传-事件总线

文章目录 Vue的组件嵌套Vue组件化-组件间通信父子组件之间通信非父子组件间的通信 Vue的组件嵌套 前面我们是将所有的逻辑放到一个App.vue中: 在之前的案例中&#xff0c;我们只是创建了一个组件App;如果我们一个应用程序将所有的逻辑都放在一个组件中&#xff0c;那么这个组…

linux下一次复制cp多个文件(含scp命令)

linux cp 参数说明 -a&#xff1a;此选项通常在复制目录时使用&#xff0c;它保留链接、文件属性&#xff0c;并复制目录下的所有内容。其作用等于dpR参数组合。 -d&#xff1a;复制时保留链接。这里所说的链接相当于Windows系统中的快捷方式。 -f&#xff1a;覆盖已经存在的目…

实训笔记6.5

实训笔记 6.5一、座右铭二、上周回顾Java基本语法1、Java的安装和环境变量的配置2、Java的标识符、关键字和保留字3、Java中的变量和常量、字面量4、数据类型5、运算符6、流程控制7、数组8、JVM内存图9、面向对象的两大概念-类和对象 三、类的组成3.1 属性的声明和使用3.1.1 属…

扩散模型之DDPM

扩散模型之DDPM 文章前置生成模型总结 Design of DDPM正向加噪过程反向去噪过程 文章前置 最原文链接&#xff08;英文&#xff09;&#xff1a;What are Diffusion Models? 原文链接&#xff1a;Diffusion扩散模型大白话讲解&#xff0c;看完还不懂&#xff1f;不可能 原文链…

第10章 对象和类

第10章 对象和类 10.1 过程性编程和面相对象编程10.2 抽象和类10.2.1 类型是什么10.2.2 C中的类10.2.3 实现类成员函数10.2.4 使用类 10.1 过程性编程和面相对象编程 采用OOP方法时&#xff0c;首先从用户的角度考虑对象——描述对象所需的数据以及描述用户与数据交互所需的操…

【蓝桥刷题】备战国赛——异或三角

蓝桥杯2021国赛真题——异或三角 &#x1f680; 每日一题&#xff0c;冲刺国赛 &#x1f680; 题目导航&#xff1a; 异或三角 &#x1f387;思路&#xff1a;数位 d p dp dp d f s dfs dfs 思维 &#x1f531;思路分析&#xff1a; ✅数理基础&#xff1a; 按位异或&am…

(2017,AdaIN)用自适应实例归一化进行实时的任意风格迁移

Arbitrary Style Transfer in Real-time with Adaptive Instance Normalization 公众号&#xff1a;EDPJ 目录 ​​​​​​​0. 摘要 1. 简介 2. 相关工作 3. 背景 3.1 批量归一化&#xff08;Batch Normalization&#xff0c;BN&#xff09; 3.2 实例归一化&#xff…

入驻京东直播间、成功借壳上市,交个朋友和时间“交朋友”

交个朋友一直走在“交朋友”的路上。 5月31日晚&#xff0c;交个朋友正式入驻京东直播间&#xff0c;首播销售额超1.5亿元&#xff0c;直播热度榜达人榜第一名&#xff0c;累计访问人次超1700万。据了解&#xff0c;京东618期间&#xff0c;除了日常直播外&#xff0c;交个朋友…

java并发编程:可见性、原子性、有序性三大特性详解

文章目录 可见性导致可见性的原因线程交叉执行重排序结合线程交叉执行共享变量更新后没有及时更新 如何解决可见性问题 原子性出现原子性问题的原因如何解决原子性问题 有序性导致有序性的原因如何解决有序性问题 总结 可见性 内存可见性&#xff0c;指的是线程之间的可见性&am…

IPv6NAT-PT实验:IPv4和IPv6地址转换的配置和验证

IPv6NAT-PT实验&#xff1a;IPv4和IPv6地址转换的配置和验证 【实验目的】 熟悉IPv6NAT-PT的概念。 掌握静态IPv6NAT-PT的配置 掌握动态IPv6NAT-PT的配置。 验证配置。 【实验拓扑】 设备参数如下表所示。 设备 接口 IP地址 子网掩码 默认网关 R1 S0/0 192.168.12…

2023HW护网红队必备工具总结

一、信息收集 1、AppInfoScanner 一款适用于以HVV行动/红队/渗透测试团队为场景的移动端(Android、iOS、WEB、H5、静态网站)信息收集扫描工具&#xff0c;可以帮助渗透测试工程师、红队成员快速收集到移动端或者静态WEB站点中关键的资产信息并提供基本的信息输出,如&#xff…

Java设计模式—模板方法模式

前言&#xff1a;模板方法模式是模板模式的一个具体实现&#xff0c;它定义了一个抽象类&#xff0c;其中包含一个模板方法和若干个基本方法。其中模板方法定义了算法骨架&#xff0c;而基本方法则由子类来实现。因此&#xff0c;模板方法在定义算法的结构方面提供了支持&#…