【C++】构造函数与析构函数

news2025/1/18 16:52:14

写在前面

构造函数与析构函数都是属于类的默认成员函数!
默认成员函数是程序猿不显示声明定义,编译器会中生成。

构造函数和析构函数的知识需要建立在有初步类与对象的基础之上的,关于类与对象不才在前面笔记中有详细的介绍:点我跳转


文章目录

  • 写在前面
  • 一、构造函数的特性
    • 1.1、函数名与类名相同。
    • 1.2、 无返回值。
    • 1.3、 对象实例化时编译器自动调用对应的构造函数。
    • 1.4、构造函数可以重载。
    • 1.5、如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义编译器将不再生成。
    • 1.6、无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个。
    • 1.7、构造函数的初始化列表
  • 二、析构函数
    • 2.1、析构函数名是在类名前加上字符 ~
    • 2.2、无参数无返回值类型
    • 2.3、一个类只能有一个析构函数。
    • 2.4、对象生命周期结束时,C++编译系统系统自动调用析构函数。
    • 2.5、编译器生成的默认析构函数,对自定类型成员调用它的析构函数
    • 2.6、如果类中没有申请资源时,析构函数可以不写,直接使用编译器生成的默认析构函数


一、构造函数的特性

构造函数是特殊的成员函数,需要注意的是,构造函数虽然名称叫构造,但是构造函数的主要任务并不是开空间创建对象,而是初始化对象

其特征如下:

1.1、函数名与类名相同。

1.2、 无返回值。

1.3、 对象实例化时编译器自动调用对应的构造函数。

在这里插入图片描述

class stack {
public:
	stack() {//构造函数
		cout << "this is stack()" << endl;
	}
	
	void Init(int defintCapacity) {
		_arr = (int*)calloc(defintCapacity, sizeof(int));
		if (nullptr == _arr)
		{
			perror("malloc申请空间失败");
			return;
		}
		_capacity = defintCapacity;
		_size = 0;
	}

	void push(int x) {
		//....扩容等
		_arr[_size++] = x;
	}
private:
	int* _arr;
	int _size;
	int _capacity;
};

int main() {
	stack s1;

	return 0;
}

程序运行结果:
在这里插入图片描述

  • 在上述代码中,不才创建了一个默认构造函数stack,在构造函数中,我们只让其打印字符串this is stack(),之后,我们在s1对象中,并没有显示的调用构造函数,但是字符串就被打印出来了,这就说明的对象实例化时编译器自动调用对应的构造函数

这时候,我们就可以把stack的初始化函数设置放入构造函数中,每当我们创建一个对象时,通过构造函数自动初始化数据。如下:

class stack {
public:
	stack(int defintCapacity = 4) {
		_arr = (int*)calloc(defintCapacity, sizeof(int));
		if (nullptr == _arr)
		{
			perror("malloc申请空间失败");
			return;
		}
		_capacity = defintCapacity;
		_size = 0;
	}

	void push(int x) {
		//....扩容等
		_arr[_size++] = x;
	}
private:
	int* _arr;
	int _size;
	int _capacity;
};

int main() {
	stack s1;

	return 0;
}

运行结果:
在这里插入图片描述

  • 这时候,我们就不用每次都显示的初始化数据了,而且也不怕忘记初始化。

1.4、构造函数可以重载。

构造函数也是函数,是函数就可以重载
在这里插入图片描述

class stack {
public:
	stack(int defintCapacity = 4) {
		_arr = (int*)calloc(defintCapacity, sizeof(int));
		if (nullptr == _arr)
		{
			perror("malloc申请空间失败");
			return;
		}
		_capacity = defintCapacity;
		_size = 0;
	}

	stack(int* arr, int defintCapacity) {
		if (nullptr == arr) {
			perror("malloc申请空间失败");
			return;
		}
		_arr = arr;
		_capacity = defintCapacity;
		_size = 0;
	}

	void push(int x) {
		//....扩容等
		_arr[_size++] = x;
	}
private:
	int* _arr;
	int _size;
	int _capacity;
};

int main() {
	int* arr = (int*)calloc(2, sizeof(int));

	stack s1(arr, 2);

	return 0;
}

程序运行结果:
在这里插入图片描述
和函数重载一样的逻辑,编译器会根据符号名去调用对应的构造函数。
需要注意,调用默认构造函数不需要加括号,因为加上括号后,编译器会认为是函数

举个栗子:
stack s1:这时s1代表的是调用stack的默认构造函数的对象
stack s1():这时s1就被当做,返回值是stack类且没有形参的函数。
有参调用就和普通函数一样,只不过是对象+参数列表stack s1(arr, 2)


1.5、如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义编译器将不再生成。

默认构造函数在C++中有特殊定义,在C++标准中,默认构造函数不会对内置类型进行处理,自定义类型会调用它的默认构造函数。但是现在有些编译器会对内置类型进行初始化,但这是该编译器自己的行为,C++标准中是不进行处理的。

内置类型/基本类型:语言本身定义的基础类型(如intchar、指针、double等)
自定义类型:使用classstruct等定义的类型

在这里插入图片描述

class stack {
public:
	stack(int defintCapacity = 4) {
		_arr = (int*)calloc(defintCapacity, sizeof(int));
		if (nullptr == _arr)
		{
			perror("malloc申请空间失败");
			return;
		}
		_capacity = defintCapacity;
		_size = 0;
	}

	stack(int* arr, int defintCapacity) {
		if (nullptr == arr) {
			perror("malloc申请空间失败");
			return;
		}
		_arr = arr;
		_capacity = defintCapacity;
		_size = 0;
	}

	void push(int x) {
		//....扩容等
		_arr[_size++] = x;
	}
private:
	int* _arr;
	int _size;
	int _capacity;
};

class Date
{
public:

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

private:
	int _year;
	int _month;
	int _day;
};
int main() {
	Date d1;

	return 0;
}

程序运行结果:(在vs2022环境下)
在这里插入图片描述

在默认构造函数中,并不会对定义类型进行任何操作,貌似不能证明默认构造函数的存在,但是我们把Date类设置为,下程序时:

class stack {
public:
	stack(int defintCapacity = 4) {
		_arr = (int*)calloc(defintCapacity, sizeof(int));
		if (nullptr == _arr)
		{
			perror("malloc申请空间失败");
			return;
		}
		_capacity = defintCapacity;
		_size = 0;
	}

	stack(int* arr, int defintCapacity) {
		if (nullptr == arr) {
			perror("malloc申请空间失败");
			return;
		}
		_arr = arr;
		_capacity = defintCapacity;
		_size = 0;
	}

	void push(int x) {
		//....扩容等
		_arr[_size++] = x;
	}
private:
	int* _arr;
	int _size;
	int _capacity;
};

class Date
{
public:

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

private:
	//内置类型
	int _year;
	int _month;
	int _day;
	//自定义类型
	stack _st;
};

int main() {
	Date d1;

	return 0;
}

运行结果:(在VS2013编译器中)
在这里插入图片描述

  • 在vs2013中,我们可以清晰看出内置类型不会进行处理的,而自定义类型会调用其默认构造函数

但是我们在VS2022中尝试一下

在这里插入图片描述

  • 我们发现在vs2022编译环境下,有自定义类型情况中,内置类型会被初始化为0,在上例中,我们也发现,在没有自定义类型情况中,内置类型是不会处理的

所以,不才推荐在C++中类中,我们默认内置类型是未被处理的,自定义类型是会调用其默认构造函数的,这样不会出现程序运行错误。

C++11后,对成员变量做了一个补丁,可以在声明成员变量时给定一个缺省值。

在这里插入图片描述
这里不才以内置类型为例,

class Date
{
public:
	Date(){}
	Date(int year, int month, int day) {
		_year = year;
		_month = month;
		_day = day;
	}
	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}

private:
	//内置类型 
	//这里不是初始化,而是声明
	//这里给的是默认缺省值,给编译器生成默认构造函数时使用
	int _year = 1;
	int _month = 1;
	int _day = 1;

};

int main() {
	Date d1;
	d1.Print();
	return 0;
}

程序运行结果:

在这里插入图片描述
如果我们调用默认构造函数,那么内置类型的值就是程序猿给定的缺省值。如果我们调用不是默认构造函数,那么使用的就是自定义构造函数的值,如下图。
在这里插入图片描述

什么情况下可以直接使用默认构造函数:

  • 内置类型成员都有缺省值,且初始化符合要求
  • 全部都是自定义类型成员,且这些类型都定义了默认构造函数。

1.6、无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个。

虽然在语法中,无参的构造函数和全缺省的构造函数形参了函数重载,编译不会有错,但是在对象初始化时,无参调用存在歧义。

在这里插入图片描述

class Date
{
public:
	Date() {}

	Date(int year = 2035, int month = 1, int day = 1) {
		_year = year;
		_month = month;
		_day = day;
	}
	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}

private:
	int _year = 1;
	int _month = 1;
	int _day = 1;

};

int main() {
	Date d1;
	d1.Print();
	return 0;
}

程序运行结果:

在这里插入图片描述

  • 无参构造函数和全缺省的构造函数都是不需要传参调用的,所以在函数调用时,就会报错对重载函数的调用不明确

无参构造函数全缺省构造函数、我们没写编译器默认生成的构造函数,只要不传参就可以调用的,都可以认为是默认构造函数,而默认构造函数只能存在一个!

1.7、构造函数的初始化列表

构造函数体赋值

在上述的构造器中,我们构造函数内进行的操作是构造函数体赋值,这些操作只是赋值,并不是属性的初始化定义。如下

class Date
{
public:
	Date(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;
};
  • _year = year; _month = month;_day = day;这些在构造器中只是充当赋值的作用,并不是对属性_year_month_day的初始化定义。因为初始化只能初始化一次,而构造函数体内可以多次赋值。

初始化列表把类中的所有属性进行初始化定义

初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个 “成员变量” 后面跟一个放在括号中的初始值或表达式。如下代码

class Date
{
public:
	Date(int year, int month, int day)
		:_year(year)
		,_month(month)
		,_day(day)
		//,_day(day) err:最多只能出现一次
	{
		
	}
private:
	int _year;
	int _month;
	int _day;
};
  1. 每个成员变量在初始化列表中最多只能出现一次(初始化只能初始化一次)
  2. 类中包含以下成员必须在初始化列表位置进行初始化
    • 引用成员变量
    • const成员变量
    • 自定义类型成员(且该类没有默认构造函数时)

因为引用成员变量const成员变量在初始化时,必须要进行赋值。而自定义类型成员。构造函数编译器只会调用自定义类型的默认构造函数,如果没有默认构造函数的情况编译器就无法找到自定义类型所对应的构造函数。

在这里插入图片描述
引用成员变量const成员变量 不在初始化列表进行初始化。而在构造函数体赋值中进行赋值来达到初始化。

在这里插入图片描述

自定义类型在没有默认构造函数的情况下,让编译器自己去寻找默认构造函数。

在这里插入图片描述
所以我们就必须在属性初始化的时候赋初值。如下代码:

class A {
public:
	A(int a)
		:_a(a)
	{	}
private:
	int _a = 0;
};

class Date
{
public:
	Date(int year, int month, int day)
		:_year(year)
		,_month(month)
		,aa(10)
	{
		
	}
private:
	A aa;
	const int _year;
	int& _month;
	int _day;
};

尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使用初始化列表初始化。 对于内置类型也是在初始化列表中进行初始化。

我们属性都是在初始化列表中进行初始化构造函数体赋值一般是完成初始化列表不能完成的工作。如检查动态开辟内存是否为空等操作。
在这里插入图片描述

class stack {
public:
	stack(int size)
		:_arr( (int*)malloc(sizeof(int) * size) )
		,_capacity(0)
		,_size(size)
	{
		//检查_arr动态开辟的空间是否为空
		if (_arr == nullptr) {
			perror("malloc::>");
			exit(1);
		}

		//再把_arr初始化为0
		memset(_arr, 0, (sizeof(int) * size) );
	}

private:
	int* _arr;
	int _capacity;
	int _size;
};

int main() {
	stack s1(10);
	return 0;
}

成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关

在这里插入图片描述
在上述的stack类中,很多小伙伴在动态开辟_arr的初始化时,先在初始化列表时把_size放在了_arr的前面,之后把_arr计算空间大小的size使用了属性的_size这样导致的程序崩溃

class stack {
public:
	stack(int size)
		: _capacity(0)
		, _size(size)
		,_arr( (int*)malloc(sizeof(int) * _size) )
		
	{
		//检查_arr动态开辟的空间是否为空
		if (_arr == nullptr) {
			perror("malloc::>");
			exit(1);
		}

		//再把_arr初始化为0
		memset(_arr, 0, (sizeof(int) * size) );
	}

private:
	int* _arr;
	int _capacity;
	int _size;
};

int main() {
	stack s1(10);

	return 0;
}
  • 这时候初始化顺序是先初始化_arr数组,此时_size并没有被初始化,那么这时候_size就是一个随机值。
  • 我们使用一个巨大的随机值去动态开辟一个空间,那么动态开辟出来的空间也是一个巨大的空间,所以程序会崩溃。
  • 只有初始化完了_arr数组,再初始化_capacity,最后初始化_size

为了深刻理解:我们再举个栗子,下面程序运行结果是什么。

class A
{
public:
	A(int a)
		:_a1(a)
		, _a2(_a1)
	{}
	void Print() {
		cout << _a1 << " " << _a2 << endl;
	}
private:
	int _a2;
	int _a1;
};

int main() {
	A aa(20);
	aa.Print();
}
  • 根据我们理解的:成员变量在类中声明次序就是其在初始化列表中的初始化顺序,此时程序的运行结果为:20 随机值

不才这里建议:声明的顺序与初始化列表顺序保持一致

二、析构函数

析构函数:与构造函数功能相反析构函数不是完成对对象本身的销毁局部对象销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数完成对象中资源的清理工作

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

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

2.2、无参数无返回值类型

2.3、一个类只能有一个析构函数。

若未显式定义,系统会自动生成默认的析构函数。注意:析构函数没有形参所以不能重载

2.4、对象生命周期结束时,C++编译系统系统自动调用析构函数。

在这里插入图片描述

class Date
{
public:
	Date() {
		cout << "Date()" << endl;
	}

	Date(int year, int month, int day) {
		_year = year;
		_month = month;
		_day = day;
	}
	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}

	~Date() {
		cout << "~Date()" << endl;
	}

private:
	int _year = 1;
	int _month = 1;
	int _day = 1;

};

int main() {
	Date d1;
	{//创建了代码块用于验证:对象生命周期结束时,C++编译系统系统是否会自动调用析构函数
		Date d2;
		d2.Print();
		printf("\n");

		cout << &d2 << endl;
	}
	printf("\n");

	d1.Print();
	return 0;
}

程序运行结果:

在这里插入图片描述


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

在这里插入图片描述

class stack {
public:
	stack(int defintCapacity = 4) {
		_arr = (int*)calloc(defintCapacity, sizeof(int));
		if (nullptr == _arr)
		{
			perror("malloc申请空间失败");
			return;
		}
		_capacity = defintCapacity;
		_size = 0;

		cout << "stack()" << endl;
	}

	stack(int* arr, int defintCapacity) {
		if (nullptr == arr) {
			perror("malloc申请空间失败");
			return;
		}
		_arr = arr;
		_capacity = defintCapacity;
		_size = 0;
	}

	void push(int x) {
		//....扩容等
		_arr[_size++] = x;
	}

	~stack() {
		free(_arr);
		_arr = nullptr;
		cout << "~stack()" << endl;
	}
private:
	int* _arr;
	int _size;
	int _capacity;
};

class Date
{
public:
	Date() {
		cout << "Date()" << endl;
	}

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

private:
	//内置类型 给定缺省值
	int _year = 1;
	int _month = 1;
	int _day = 1;
	//自定义类型
	stack _st;
};

int main() {
	Date d1;
	d1.Print();
	return 0;
}

程序运行结果:

在这里插入图片描述

  • main方法中创建了Date对象d1,而d1中包含4个成员变量,其中_year, _month,_day三个是内置类型成员,销毁时不需要资源清理,最后系统直接将其内存回收即可。
  • 但是_ststack类的对象,所以在d1销毁时,要将其内部包含的stack类的_st对象销毁,所以要调用stack类的析构函数
  • main函数中不能直接调用stack类的析构函数,实际要释放的是Date类对象,所以编译器会调用Date类的析构函数,而Date没有显式提供,则编译器会给Date生成一个默认的析构函数,目的是在其内部调用stack类的析构函数,即当Date对象销毁时,要保证其内部每个自定义对象都可以正确销毁

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

析构函数的使用:

  1. 一般情况下,有动态申请资源 ,就需要显示写析构函数释放资源
  2. 没有动态申请资源,不需要写析构函数
  3. 需要释放资源的类型都是自定义类型,在该类中就不需要写析构函数。因为默认生成的析构函数遇到自定义类型会自动调用自定义类型的析构函数
  4. 特殊场景特殊使用

以上就是本章所有内容。若有勘误请私信不才。万分感激💖💖 如果对大家有用的话,就请多多为我点赞收藏吧~~~💖💖
请添加图片描述

ps:表情包来自网络,侵删🌹

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

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

相关文章

1月17日星期五今日早报简报微语报早读

1月17日星期五&#xff0c;农历腊月十八&#xff0c;早报#微语早读。 1、广东明确旅馆承担防偷拍责任&#xff1a;应确保客房没有偷窥等设备&#xff1b; 2、商务部&#xff1a;手机补贴不用交旧手机&#xff1b; 3、中国汽车工业协会&#xff1a;坚决反对拜登政府禁止使用中…

【Linux】gdb_进程概念

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &#x1f4e2;本文由 JohnKi 原创&#xff0c;首发于 CSDN&#x1f649; &#x1f4e2;未来很长&#…

深入内核讲明白Android Binder【二】

深入内核讲明白Android Binder【二】 前言一、Binder通信内核源码整体思路概述1. 客户端向服务端发送数据流程概述1.1 binder_ref1.2 binder_node1.3 binder_proc1.4 binder_thread 2. 服务端的binder_node是什么时候被创建的呢&#xff1f;2.1 Binder驱动程序为服务创建binder…

记录一次微信小程序使用云能力开发的过程

对于开发微信小程序云开发不知从何起的同学们&#xff0c;可以当作一次参考。虽说官方有文档&#xff0c;有模板示例&#xff0c;但是这些都是片段或者完整的结果展示。对于初学或者开发经验较少的同学们&#xff0c;可能不知先从那里入手进行第一步的开发。下面解析下构建微信…

初学stm32 --- SPI驱动25Q128 NOR Flash

目录 SPI介绍 SPI结构框图介绍 SPI外设对应的引脚 SPI数据发送与接收 SPI工作原理 SPI 全双工模式的通信机制 从机返回主机之前保存的数据 SPI工作模式介绍 SPI相关寄存器介绍&#xff08;F1 / F4 / F7&#xff09; SPI控制寄存器1&#xff08;SPI_CR1&#xff09; SPI状…

数据库基础练习1(创建表,设置外键,检查,不为空,主键等约束)安装mysql详细步骤

安装MySQL详细步骤 1. 下载 MySQL 安装程序 访问 MySQL 官方网站&#xff1a;MySQL Downloads。在下载页面&#xff0c;选择 "MySQL Community (GPL) Downloads"。在 "MySQL Community Server" 部分&#xff0c;根据你的操作系统&#xff08;Windows&…

[c语言日寄](bit)位检查——初探字节之下

哈喽大家好啊&#xff0c;在今天的快乐刷题中&#xff0c;我遇到了一个很有意思的题目&#xff1a; 题目 统计二进制中1的个数 基本思路 没错……这道题的对象比较特殊。 不同于过去常见的题目&#xff0c;之前的题目的对象都是基本数据类型&#xff0c;而这道题的对象却是…

基于SpringCloud的广告系统设计与实现(一)

一、广告系统概论 广告系统中计费方式&#xff1a;CPM 千次广告展现收费/CPT 按时间段/CPC用户点击类广告收费。 Mysql&#xff1a;进行广告数据的存储&#xff0c;以及检索系统监听Mysql做增量索引 Kafka:实现各微服务之间的通信 比如地域维度&#xff0c;时间维度 二、微服务…

React Native的现状与未来:从发展到展望

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

Python在多个Excel文件中找出缺失数据行数多的文件

本文介绍基于Python语言&#xff0c;针对一个文件夹下大量的Excel表格文件&#xff0c;基于其中每一个文件内、某一列数据的特征&#xff0c;对其加以筛选&#xff0c;并将符合要求与不符合要求的文件分别复制到另外两个新的文件夹中的方法。 首先&#xff0c;我们来明确一下本…

【JSqlParser】Java使用JSqlParser解析SQL语句总结

简述 Java解析SQL语句有很多工具都可以做到&#xff0c;比如Mybatis、Druid、目前用来用去最全面的仍然是Jsqlparser&#xff0c;它是一个Github上的开源项目&#xff0c;JSqlParser是一个用于解析SQL语句的Java库&#xff0c;它可以帮助开发者分析和操作SQL语句的结构。无论是…

WINFORM - DevExpress -> alertControl1提示信息框

第一个按钮为常规按钮, 单击触发 ButtonClick 事件. 第二个按钮有选中和未选中状态. 单击触发 ButtonDownChanged 事件。 if (e.ButtonName "alertButton2") { } 在dev用户界面中进行提示(usecontrolwinform) AlertInfo info new AlertInfo("提示",…

springboot全局异常处理示例

这种错误交给前端无法处理。 需要自定义一些错误响应类给前端 package cn.yam.bloomfilter.exception;import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.ht…

Windows远程桌面网关出现重大漏洞

微软披露了其Windows远程桌面网关&#xff08;RD Gateway&#xff09;中的一个重大漏洞&#xff0c;该漏洞可能允许攻击者利用竞争条件&#xff0c;导致拒绝服务&#xff08;DoS&#xff09;攻击。该漏洞被标识为CVE-2025-21225&#xff0c;已在2025年1月的补丁星期二更新中得到…

Shell正则表达式与文本处理三剑客(grep、sed、awk)

一、正则表达式 Shell正则表达式分为两种&#xff1a; 基础正则表达式&#xff1a;BRE&#xff08;basic regular express&#xff09; 扩展正则表达式&#xff1a;ERE&#xff08;extend regular express&#xff09;&#xff0c;扩展的表达式有、?、|和() 1.1 基本正则表…

基于 Spring Boot 和 Vue.js 的全栈购物平台开发实践

在现代 Web 开发中&#xff0c;前后端分离的架构已经成为主流。本文将分享如何使用 Spring Boot 和 Vue.js构建一个全栈购物平台&#xff0c;涵盖从后端 API 开发到前端页面实现的完整流程。 1. 技术栈介绍 后端技术栈 JDK 1.8&#xff1a;稳定且广泛使用的 Java 版本。 Spring…

Golang Gin系列-3:Gin Framework的项目结构

在Gin教程的第3篇&#xff0c;我们将讨论如何设置你的项目。这不仅仅是把文件扔得到处都是&#xff0c;而是要对所有东西的位置做出明智的选择。相信我&#xff0c;这些东西很重要。如果你做得对&#xff0c;你的项目会更容易处理。当你以后不再为了找东西或添加新功能而绞尽脑…

网络编程-UDP套接字

文章目录 UDP/TCP协议简介两种协议的联系与区别Socket是什么 UDP的SocketAPIDatagramSocketDatagramPacket 使用UDP模拟通信服务器端客户端测试 完整测试代码 UDP/TCP协议简介 两种协议的联系与区别 TCP和UDP其实是传输层的两个协议的内容, 差别非常大, 对于我们的Java来说, …

3.数据库系统

3.1数据库的基本概念 3.1.1:数据库体系结构 3.1.1.1集中式数据库系统 数据是集中的 数据管理是集中的 数据库系统的素有功能(从形式的用户接口到DBMS核心)都集中在DBMS所在的计算机 3.1.1.2C/S结构 客户端负责数据表示服务服务器主要负责数据库服务 数据库系统分为前端和后端…

探索 Transformer²:大语言模型自适应的新突破

目录 一、来源&#xff1a; 论文链接&#xff1a;https://arxiv.org/pdf/2501.06252 代码链接&#xff1a;SakanaAI/self-adaptive-llms 论文发布时间&#xff1a;2025年1月14日 二、论文概述&#xff1a; 图1 Transformer 概述 图2 训练及推理方法概述 图3 基于提示的…