C++初阶语法——类和对象

前言:C语言中的结构体,在C++有着更高位替代者——类。而类的实例化叫做对象。
本篇文章不定期更新扩展后续内容。

目录

  • 一.面向过程和面向对象初步认识
  • 二.类
    • 1.C++中的结构体
    • 2.类的定义
      • 类的两种定义方式
    • 3.类的访问限定符及封装
      • 访问限定符说明
    • 4.类的实例化
      • 对象只存储成员变量,不存储成员函数
      • 成员函数存储在公共代码区
    • 5.this指针
  • 三.六大默认成员函数
    • 1.构造函数
      • 构造函数特点
      • 默认构造函数
      • 初始化列表
    • 2.析构函数
      • 析构函数特点
    • 三 .拷贝构造函数
      • 浅拷贝问题——指向同一块空间
      • 拷贝构造
      • 深拷贝
      • 拷贝构造特点:

一.面向过程和面向对象初步认识

在学习C语言的时候,我就时常听说过面向过程和面向对象,但是对这两个概念的认知非常模糊,那么这两者有什么区别呢?

C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。
而C++是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成。我们不需要关注过程是怎么完成的,我们只需要关注对象间的交互。
面向对象有3大特性——封装,继承,多态。

二.类

1.C++中的结构体

C语言中结构体中只能定义变量,而在C++中,结构体中不仅能定义变量,还可以定义函数(struct升级成了类)。

以数据结构——栈为例:
直接在结构体内定义函数。
实例化对象时,无需再写struct,只需写结构体名。

#include<iostream>
using namespace std;
typedef struct Stack {
	int* a;
	int capacity;
	int top;
	void Init()   //定义函数
	{
		a = nullptr;
		capacity = 0;
		top = 0;
	}
}ST;
int main()
{
	Stack s1; // 无struct
	s1.Init();
	return 0;
}

2.类的定义

在C++中,类更喜欢用class而非struct。
这两者在默认访问限定上有些区别,struct默认为public,而class默认为private,更符合面向对象的要求。这也是为什么更喜欢使用class。该点在下文默认访问限定符也会讲解。

class Classname
{
	//类体:成员函数+成员变量

};  //跟结构体一样有分号不要忘

class为定义类的关键字,Classname为类名,{}中为类的主体,类体中的内容称为类的成员,类中的变量称为类的属性或成员变量,类中的函数称为类的方法或成员函数。

类的两种定义方式

一种就是向上面的栈一样将函数声明定义都写在类里面,值得一提的是,这种函数会被编译器当成内联函数。
还有一种就是将类声明放在头文件中,在源文件中定义函数,但是需要注意的是,成员函数名前需要加类名::(域作用限定符),一般第二种用的更多。

//obj.h
#include<iostream>
using namespace std;

typedef struct Stack {
	int* a;
	int capacity;
	int top;
	void Init();
}ST;

//test.cpp
#include"obj.h"
void Stack::Init()  // 类名::
{
	a = nullptr;
	capacity = top = 0;
}

3.类的访问限定符及封装

C++实现封装的方式:用类将对象的属性(成员变量)和方法(成员函数)结合在一起,让对象更加完善,通过访问限定符选择性的将其接口提供给外部的用户使用。

共有3种访问限定符:在诸如php,java等语言中都有。
这里是引用

访问限定符说明

利用好访问限定符,可以有效保护好类中的数据,防止其他人随便访问。
1.public:公有的类成员可以在任何地方被访问。
protect:受保护的类成员则可以被其自身以及其子类和父类访问。
private:私有的类成员则只能被其定义所在的类访问。
(在学继承之前,protect和private使用起来没差)
2.struct默认为public,class默认为private。
3.访问权限作用域从该访问限定符开始到下一个访问限定符出现。
4.如果后面没有访问限定符,作用域到 } 为止。
5.一般情况下,成员变量都设置为private。

以日期类为例:

class Date {
public:
	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;  //声明,没有定义,不占空间
	int _month;
	int _day;
};

4.类的实例化

用类创建对象的过程,叫做类的实例化。
1.类是对对象进行描述的,是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没有分配实际的内存空间来存储它。
2.一个类可以实例化出多个对象。实例化出的对象才占用实际的内存空间,且只存储成员变量,不存储成员函数。

以日期类为例:

class Date {
public:
	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;  //声明,没有定义,不占空间
	int _month;
	int _day;
};

int main()
{
	
	Date d1;  // 类的实例化
	Date d2, d3;  // 一个类可以实例化出多个对象
	//下面两行代码可行吗,为什么?
	//Date::_year = 1;  //并没有实例化对象,只是声明没有开空间,更不必说初始化了。
	//d1._year = 1; //实例化了呢?也不行,因为_year是私有成员变量,只能在Date类中更改。
	return 0;
}

对象只存储成员变量,不存储成员函数

上文说过,类的主体有两个:成员变量和成员函数。
但实际上实例化的对象中只存储成员变量,而成员函数存储在公共代码区。

请看下例代码(类的空间大小计算和结构体一样,遵循结构体内存对齐规则):

class Date {
public:
	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;   //声明,没有定义,不占空间
	int _month;
	int _day;
};

int main()
{
	Date s1;
	cout << sizeof(Date) << endl;
	cout << sizeof(s1) << endl;
	return 0;
}

控制台输出如下:
在这里插入图片描述
可以发现,12是只计算成员变量得到的结果,因此可以得知对象中并不存储成员函数。

之所以这样是因为成员函数对每个对象都是一样的,其会被存储在公共代码区,这样不必要在每次实例化对象时都存储一次成员函数,大大提高了程序效率。
在这里插入图片描述

成员函数存储在公共代码区

请看如下代码,各位觉得能够运行成功吗?

class Example
{
public:
	void Print()
	{
		cout << "Print()" << endl;
	}
private:
	int _a;
	int _b;
};
int main()
{
	Example* s1 = nullptr;
	s1->Print();  //空指针指向????
	return 0;
}

控制台显示如下:
在这里插入图片描述
运行成功了,为什么呢?上面不是空指针解引用问题吗,程序应该崩溃呀?
答:上面说过成员函数存储在公共代码区,直接向公共代码区call该函数的地址,不需要向对象s1中找东西,因此不会发生空指针解引用操作。

5.this指针

类的成员函数中都隐藏了一个this指针参数。
this在实参和形参位置不能显示写,但是可以在类里面显示的用。
this指针不可被更改.
this指针可以为空(就是上面成员函数存在公共代码区的例子)。
this指针存在栈帧里面。(不要误以为this存在对象中,this就是一个形参,跟普通形参一样存在栈帧里面)。

仍以日期类为例:

class Date {
public:
	//this在实参和形参中不能显示地写
	//在类中可以显示地用(没什么价值)
	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	/*void Init(Date* const this ,int year, int month, int day)
	{
		this->_year = year;
		this->_month = month;
		this->_day = day;
	}*/
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1;
	d1.Init(2023, 8, 11); //d1.Init(&d1,2023,8,11);
	return 0;
}

三.六大默认成员函数

C++中有六个默认成员函数,我们不写的话,它们会自动生成。

在这里插入图片描述

1.构造函数

构造函数最便捷的地方就是自动调用,可以在我们忘了初始化的时候发挥作用。

构造函数是特殊的成员函数,需要注意的是,构造函数虽然名称叫构造,但是构造函数的主要任务并不是开空间创建对象,而是初始化对象
其特征如下:
1.函数名和类名相同
2.无返回值(不需要写void)。
3.对象实例化时编译器自动调用对应的构造函数。
4.构造函数可以重载。(可以写多个构造函数,提供多种初始化方式)

class Date {
public:
	//构造函数,函数名和类名相同。
	Date(int year = 1, int month = 1, int day = 1) //全缺省参数
	{
		cout << "Date()" << endl;  // 借此观察构造函数是否被调用
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1(2023,8,11); // 对象实例化时自动调用构造函数,一定记住!!! 实参可以任意更改
	//在对象d1后面接实参是构造函数的特殊的初始化规则。 
	//Date d2(); //不可以在对象后加括号而不给实参,因为编译器分不清你是在创建对象还是调用函数。
	return 0;
}

控制台输出如下:可以看到,我们并没有调用Date函数,Date函数在对象实例化时自动调用了。
在这里插入图片描述

构造函数特点

构造函数,是默认成员函数之一,我们不写,编译器也会自动生成。
编译生成的默认构造函数的特点:
1.我们写了就不会自动生成了,我们不写编译器会自动生成一个无参的默认构造函数
2.内置类型不会处理(C++11,支持声明时给缺省值,但是有了缺省值就会处理)
3.自定义类型的成员才会处理,会去调用这个成员的默认构造函数。(注意是默认构造函数,而非是构造函数)

(内置类型就是诸如int,double这种语言提供的类型,而自定义类型就是我们自己定义的类型,比如上文的Date。
需要注意的是:int* 是内置类型,Date* 也是内置类型。只要是指针就是内置类型)

默认构造函数

ps:这个地方刚开始学的时候理解起来挺难的,我被绕的晕头转向的。还是要多学多看代码啊。

切不可认为只有编译器自动生成的才是默认构造函数。 无参的构造函数和全缺省的构造函数(此两者都是我们自己写的)都被称为默认构造函数,并且默认构造函数只能有一个。
共有3种默认构造函数:
1.无参的构造函数
2.全缺省的构造函数
3.我们没写编译器自动生成的构造函数。
总结:这3种默认构造函数有一个共同点,就是不传参就可以调用。
多个默认构造函数同时存在会有歧义。

如下图所示,编译器就会显示无默认构造函数。
在这里插入图片描述
而将Date写成全缺省就可以正常运行(对应上文的全缺省的构造函数是默认构造函数)
在这里插入图片描述
·总结:一般情况下都需要我们自己写构造函数,决定初始化方式。而成员变量全是自定义类型时,可以考虑不写构造函数。

初始化列表

2.析构函数

析构函数:与构造函数的作用相反,析构函数不是完成对对象本身的销毁,局部对象的销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作(malloc,realloc出来的空间等)。
析构函数的特性:
1.析构函数名是在类名前加上字符~
2.无参数无返回值
3.一个类只能有一个析构函数。若未显示定义(我们没写),系统会自动生成默认的析构函数。注意:析构函数不能重载。
4.对象声明周期结束时,C++编译系统自动给调用析构函数。
5.后定义的对象先析构(栈帧)。

析构函数特点

跟构造函数类似,析构函数具有以下特点:
1.我们写了就不会自动生成了,我们不写编译器会自动生成一个析构函数。
2.内置类型成员不会处理。
3.自定义类型成员会调用这个成员的析构函数。

以如下代码为例:在日期类中创建了一个自定义类型A的成员变量

class A {
public:
	A()
	{
		cout << "A()" << endl;
	}
	~A()
	{
		cout << "~A()" << endl;
	}
};
class Date {
public:
	Date(int year = 1, int month = 1, int day = 1)
	{
		cout << "Date()" << endl;
		_year = year;
		_month = month;
		_day = day;
	}
	~Date()
	{
		cout << "~Date()" << endl;
	}
private:
	int _year;
	int _month;
	int _day;
	A _aa;
};
int main()
{
	Date d1;
	return 0;
}

控制台显示如下:可以看到我们只是创建了一个Date的实例化对象,但是程序先调用了A的构造函数,之后调用Date的构造函数,生命周期结束后,先调用了Date的析构函数,最后调用了A的析构函数。
因为A是自定义类型,而自定义类型成员会去调用这个成员的构造和析构函数。
在这里插入图片描述

三 .拷贝构造函数

下面将用一个问题来引出为什么需要拷贝构造。

浅拷贝问题——指向同一块空间

仍以上面的日期类为例:使用C语言常用的传值调用

//日期类代码跟上面相同,这里省略。
void Func(Date d)  //传值调用
{
} 
int main() { 	
	Date d1; 
	Func(d1); 
	return 0;
 }

控制台输入如下:
在这里插入图片描述
可以看到,析构函数调用了两次,这是因为首先在main栈帧中创建了d1,调用了构造函数,之后d1拷贝赋值给d。待到d生命周期结束,Func栈帧销毁,调用一次析构函数回收d的资源。然后d1生命周期结束,栈帧销毁回收d1的资源,调用第二次析构函数。
在这里插入图片描述

但是,上面的日期类实际上并无诸如malloc,realloc开出来的空间可清理,实际拷贝时我们并不能这样传值传参,下面再以栈举个反例:

class Stack {
public:
	Stack(size_t n = 4)
	{
		_a = (int*)malloc(sizeof(int) * n);
		_capacity = n;
		_top = 0;
	}
	~Stack()
	{
		free(_a);
	}
private:
	int* _a;
	int _top;
	int _capacity;
};
void Func(Stack s)
{
}
int main()
{
	Stack s1;
	Func(s1);
	return 0;
}

相似的代码,但是运行后程序直接崩溃了:
在这里插入图片描述
原因跟上面的日期类例子类似:Func先调用析构函数,栈帧销毁,释放_a指向的空间,而main结束再调用析构函数,释放_a指向的空间,但是刚刚这个空间已经被释放过了,_a已经是野指针,因此程序崩溃。

在这里插入图片描述

那么对此有什么解决办法吗?实际上只需要将Func传值传参改成传指针传参或者传引用传参即可。这样的话从始至终都只有一个对象s1(一个对象只会析构一次)。
在这里插入图片描述

但是,这里又提出了一个问题,怎么才能在不改变s1的情况下改变s呢?这种时候就要用到拷贝构造函数。

拷贝构造

用当前类型的对象去初始化另一个同类型对象。
C++规定自定义类型传值传参要调用拷贝构造。
拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用,在用已存在的类类型对象创建新对象时由编译器自动调用。
其特征如下:
1.拷贝构造函数是构造函数的一个重载形式。
2.拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错,因为会引发无穷递归调用。

注意特征的第二点,不能使用传值方式,可使用传引用方式。
因为使用传值方式的话,传值过去实例化出一个对象d,对象d又会去调用自己的拷贝构造函数,再实例化出一个对象…如此往复,无穷递归调用下去:

class Date {
public:
	Date(int year = 1, int month = 1, int day = 1)
	{
		cout << "Date()" << endl;
		_year = year;
		_month = month;
		_day = day;
	}
		//Date(Date d)  //拷贝构造函数——传值方式——程序崩溃
	//{
	//	cout << "Date(Date d)" << endl;
	//	_year = d._year;
	//	_month = d._month;
	//	_day = d._day;
	//}
	Date(Date& d)  //拷贝构造函数——传引用方式——正确
	{
		cout << "Date(Date d)" << endl;
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1;
	Date d2(d1);  // 拷贝构造
	Date d3 = d1; //跟上一行代码是等价的
	return 0;
}

深拷贝

刚刚类Stack发生了浅拷贝,对同一块空间释放了两次。我们可以通过拷贝构造函数避免发生这种情况。
传值传参实例化出对象s,会自动调用拷贝构造函数,将s1的数据拷贝给s,并且没有改变s1.

class Stack {
public:
	Stack(int n = 4)
	{
		cout << "Stack()" << endl;
		_a = (int*)malloc(sizeof(int) * n);
		_capacity = n;
		_top = 0;
	}
	Stack(Stack& s)   // 拷贝构造函数
	{
		_a = (int*)malloc(sizeof(int) * s._capacity);
		_top = s._top;
		_capacity = s._capacity;
	}
	~Stack()
	{
		cout << "~Stack()" << endl;
		free(_a);
	}
private:
	int* _a;
	int _top;
	int _capacity;
};
void Func(Stack s)  //自定义类型传值传参
{
}
int main()
{
	Stack s1;
	Func(s1);
	return 0;
}

拷贝构造特点:

我们不写,编译器默认生成的拷贝构造跟之前的构造函数,析构函数特点不一样。
1.自定义类型,会去调用它的拷贝构造
2. 内置类型,会对它进行值拷贝

总结:像日期类这种,我们可以不写拷贝构造默认生成的就够用了。但是像栈这种的,我们需要实现深拷贝的拷贝构造。

文末BB:对哪里有问题的朋友,尽管在评论区留言,若哪里写的有问题,也欢迎朋友们在评论区指出,博主看到后会第一时间确定修改。最后,制作不易,如果对朋友们有帮助的话,希望能给博主点点赞和关注.

在这里插入图片描述

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

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

相关文章

Python中的诡异事:不可见字符!

文章目录 前言1. 起因2. 调查3. 高能4. 释惑 前言 今天分享一件很诡异的事情&#xff0c;我写代码的时候遇到了不可见的字符&#xff01;&#xff01;&#xff01; 1. 起因 今天在使用pipreqs导出项目中所依赖的库时突然报错了&#xff1a; pipreqs . --encodingutf-8 --forc…

Spring项目整合过滤链模式~实战应用

代码下载 设计模式代码全部在gitee上,下载链接: https://gitee.com/xiaozheng2019/desgin_mode.git 日常写代码遇到的囧 1.新建一个类,不知道该放哪个包下 2.方法名称叫A,干得却是A+B+C几件事情,随时隐藏着惊喜 3.想复用一个方法,但是里面嵌套了多余的逻辑,只能自己拆出来…

百川智能发布首个530亿参数闭源大模型,今年追上GPT-3.5

4月官宣创业&#xff0c;6月15日发布第一款7B开源模型&#xff0c;7月11日发布第二款13B、130亿参数开源模型。 平均保持2个月一个版本发布速度&#xff0c;8月8日&#xff0c;百川智能发布了创业以来的首个530亿参数闭源大模型——Baichuan-53B&#xff08;以下简称“53B”&a…

Android Https

本质&#xff1a;在客户端和服务端使用非对称加密协商出一套对称密钥&#xff0c;每次发送数据前加密&#xff0c;收到后解密&#xff0c;达到加密传输 http ssl 在http之下增加了安全层&#xff0c;用于保障http的加密传输 HTTPS连接 TLS连接步骤 1.客户端发送 client h…

Ubuntu 20.04 安装 Stable Diffusionn

步骤 1&#xff1a;安装 wget、git、Python3 和 Python3虚拟环境&#xff08;如果已安装可忽略这步骤&#xff09; sudo apt install wget git python3 python3-venv步骤 2&#xff1a;克隆 SD 项目到本地 git clone https://github.com/AUTOMATIC1111/stable-diffusion-webu…

Could not resolve host: mirrorlist.centos.org; Unknown error解决方法

今天服务器安装完CentOS系统后&#xff0c;安装网络的时候&#xff0c;出现无法联网yum yum -y install net-tools 以上代码无法运行并报错&#xff0c;这里我要提醒大家&#xff0c;如果在初始安装的时候选中安装网络工具模块就不用在安装net-tools了&#xff0c;因为我选中…

C#在自动化领域的应用前景与潜力

人机界面&#xff08;HMI&#xff09;开发&#xff1a;使用C#开发人机界面软件&#xff0c;实现与自动化设备的交互和监控。C#的图形界面设计能力和丰富的控件库使得开发人员能够创建直观、易用的界面。 数据采集与处理&#xff1a;C#可以与各种传感器、设备进行数据通信和采集…

Elasticsearch之kibana相关命令

1.中文分词器相关命令 2.拼音分词器相关命令

资讯速递 | ArkUI-X 预览版已正式开源!

OpenHarmony项目群技术指导委员会&#xff08;以下简称“TSC”&#xff09;-跨平台应用开发框架TSG所孵化项目 —— ArkUI-X&#xff0c;近期已正式开源 &#xff0c;开发者基于一套主代码&#xff0c;就可以将在OpenHarmony上开发的精美、高性能应用同时运行在Android、iOS等其…

21 | 朝阳医院数据分析

朝阳医院2018年销售数据为例,目的是了解朝阳医院在2018年里的销售情况,通过对朝阳区医院的药品销售数据的分析,了解朝阳医院的患者的月均消费次数,月均消费金额、客单价以及消费趋势、需求量前几位的药品等。 import numpy as np from pandas import Series,DataFrame impo…

成功解决ubuntu-22.04的sudo apt-get update一直卡在【0% [Waiting for headers]】

成功解决ubuntu-22.04的sudo apt-get update一直卡在【0% [Waiting for headers]】 问题描述解决方案 问题描述 在下载安装包的时候一直卡在0% [Waiting for headers]&#xff0c;报错信息如下&#xff1a; Get:1 file:/var/cudnn-local-repo-ubuntu1804-8.5.0.96 InRelease […

C#随机法 双峰函数 求极值 避免落入局部最优解

避免落入局部最优解&#xff0c;只要让步长够长即可。 x1 resultX1 random1.NextDouble()*100; 如果后面不乘以100&#xff0c;则很大概率落入负数的最大值 Random random1 new Random(DateTime.Now.Millisecond);double x1 0, resultX10,max-999999,maxTemp0;for (int i …

开源语言模型的历史和重要性;Edge浏览器将推出Bing AI重写文本功能

&#x1f989; AI新闻 &#x1f680; 微软即将推出桌面版Microsoft Edge浏览器的Bing AI重写文本功能 摘要&#xff1a;微软最近在桌面版Microsoft Edge浏览器中引入了一个新功能&#xff0c;允许用户使用Bing AI重写文本。用户可以选择不同的语气、格式和长度&#xff0c;然…

✅最新!自然指数中国科研机构百强名单,出炉!

【SciencePub学术】8 月 9 日&#xff0c;自然指数官网发布了最新的中国科研机构百强名单。名单根据各大机构2022年在自然科学领域的论文贡献份额进行排名。 其中&#xff0c;中国科学院以2053.76的论文贡献份额&#xff0c;位列榜首&#xff1b;中国科学院大学和中国科学技术…

[保研/考研机试] KY80 进制转换 北京大学复试上机题 C++实现

题目链接&#xff1a; KY80 进制转换https://www.nowcoder.com/share/jump/437195121691735660774 描述 写出一个程序&#xff0c;接受一个十六进制的数值字符串&#xff0c;输出该数值的十进制字符串(注意可能存在的一个测试用例里的多组数据)。 输入描述&#xff1a; 输…

Fast SAM与YOLOV8检测模型一起使用实现实例分割

Fast SAM与YOLOV8检测模型一起使用 部分源代码在结尾处可获取 晓理紫 1 使用场景 实例分割数据集的获取要比检测数据的获取更加困难&#xff0c;在已有检测模型不想从新标注分割数据进行训练但是又想获取相关物体的mask信息以便从像素级别对物体进行操作&#xff0c;这时就可以…

模拟实现消息队列项目(系列5) -- 服务器模块(虚拟主机)

目录 前言 1. 创建VirtualHost 1.1 定义虚拟主机的相关属性 1.2 VirtualHost 构造方法 1.3 交换机和队列的创建和删除 1.3.1 交换机操作 1.3.2 队列操作 1.4 绑定的创建和删除 1.5 发送消息到指定的队列/交换机 2. 实现路由规则Router 2.1 checkBindingKey() 2.2 checkRoutin…

【软件测试】接口测试工具APIpost

说实话&#xff0c;了解APIpost是因为&#xff0c;我的所有接口相关的文章下&#xff0c;都有该APIpost水军的评论&#xff0c;无非就是APIpost是中文版的postman&#xff0c;有多么多么好用&#xff0c;虽然咱也还不是什么啥网红&#xff0c;但是不知会一声就乱在评论区打广告…

springboot项目问题

目录标题 问题后端1.[mybatis报错Parameter start not found. Available parameters are [1, 0, param1, param2]](https://www.cnblogs.com/josephcnblog/articles/7077244.html) 知识后端1. [Select 数据表的字段与实体类的属性值](https://www.cnblogs.com/yanguobin/p/1191…

【SpringBoot学习笔记】04. Thymeleaf模板引擎

模板引擎 templates下的只能通过Controller来跳转&#xff0c;templates前后端分离&#xff0c;需要模板引擎thymeleaf支持 模板引擎的作用就是我们来写一个页面模板&#xff0c;比如有些值呢&#xff0c;是动态的&#xff0c;我们写一些表达式。而这些值&#xff0c;从哪来呢…