Cpp类和对象(中续)(5)

news2024/9/22 20:52:02

文章目录

  • 前言
  • 一、赋值运算符重载
    • 运算符重载
    • 赋值运算符重载
    • 赋值运算符不可重载为全局函数
    • 前置++和后置++的重载
  • 二、const修饰成员函数
  • 三、取地址及const取地址操作符重载
  • 四、日期类的实现
    • 构造函数
    • 日期 += 天数
    • 日期 + 天数
    • 日期 -= 天数
    • 日期 - 天数
    • 日期类的大小比较
      • 日期类 > 日期类
      • 日期类 == 日期类
      • 日期类 >= 日期类
      • 日期类 < 日期类
      • 日期类 <= 日期类
      • 日期类 != 日期类
    • 日期类 - 日期类
  • 五、流插入流提取运算符重载
  • 总结


前言

  继承上节的内容,本节内容依旧量大管饱!!


一、赋值运算符重载

运算符重载

  C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,其目的就是让自定义类型可以像内置类型一样可以直接使用运算符进行操作

请记住这个目的!我们的接下来的一切都是围绕这个来展开

  运算符重载函数也具有自己的返回值类型,函数名字以及参数列表。其返回值类型和参数列表与普通函数类似。

  运算符重载函数名为:关键字operator后面接需要重载的操作符符号。

注意:

  1. 不能通过连接其他符号来创建新的操作符:比如operator@。(需要是C/C++语法中存在)
  2. 重载操作符必须有一个类类型或枚举类型的操作数。(不能去重载运算符改变内置类型的行为) -> 其实要真那么搞也可以,但是很无聊,没什么实用的
  3. 用于内置类型的操作符,重载后其含义不能改变。-> 例如内置的整型+,不能改变其含义
  4. 作为类成员的重载函数时,函数有一个默认的形参this,限定为第一个形参。
  5. sizeof 、:: 、.* 、?: 、. 这5个运算符不能重载。
  6. 并不是运算符都是需要重载的,需要看是否有存在的意义,参数部分需要对应顺序
// 来个实际例子
class Date
{
public:
	Date(int year = 0, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	
	void Print()
	{
		cout << _year << "年" << _month << "月" << _day << "日" << endl;
	}
	
	// 注意此时该函数的第一个形参默认为this指针
	bool operator==(const Date& d)// 运算符重载函数
	{
		return _year == d._year
			&&_month == d._month
			&&_day == d._day;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1(2024, 9, 22);
	Date d2 = d1;
	
	// 注意优先级
	cout << (d1 == d2) << endl; // 1
	cout << d1.operator==(d2) << endl; // 与上一条语句等价
	
	return 0;
}

  显然第一种 d1 == d2 这种形式相当明了,就好像Date真的是我们的内置类型一样,其实说白了,还是编译器帮我们化成了第二种形式,不信我们可以看下汇编形式:

在这里插入图片描述

还是那句话,当你觉得轻松的时候,总是有人为你负重前行

赋值运算符重载

 先上代码:

class Date
{
public:
	Date(int year = 0, int month = 1, int day = 1) // 构造函数
	{
		_year = year;
		_month = month;
		_day = day;
	}
	
	Date& operator=(const Date& d) // 赋值运算符重载函数
	{
		if (this != &d) // 防止会有 d1 = d1 这样自己赋值给自己
		{
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}
		return *this;
	}
	
	void Print()// 打印函数
	{
		cout << _year << "年" << _month << "月" << _day << "日" << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

我们要注意以下几点:

  1. 参数类型设置为引用,并用const进行修饰 -> 由于是自定义类型传参,我们若是使用传值传参,会额外调用一次拷贝构造函数,所以函数的第二个参数最好使用引用传参(第一个参数是默认的this指针,我们管不了)。并且我们也不改变它,那就用 const 来修饰
  2. 函数的返回值使用引用返回 -> 本质上是为了支持连续赋值,所以必须要有个返回值,而且很显然是返回左操作数 d3 = d2 = d1; 所以我们在这里返回 this 指针,且因为此时出了函数作用域this指针指向的对象并没有被销毁,所以可以使用引用返回,又省了拷贝多余的资源消耗
  3. 一个类如果没有显示定义赋值运算符重载,编译器也会自动生成一个,完成对象按字节序的值拷贝 -> 没错,赋值运算符重载编译器也可以自动生成,并且也是支持连续赋值的。但是编译器自动生成的赋值运算符重载完成的是对象按字节序的值拷贝,例如d2 = d1,编译器会将d1所占内存空间的值完完全全地拷贝到d2的内存空间中去,类似于memcpy
// 请注意区分
Date d1(2024,9,22);
Date d2 = d1; // 拷贝构造
Date d3;
d3 = d1; // 赋值

// 拷贝构造函数:用一个已经存在的对象去构造初始化另一个即将创建的对象
// 赋值运算符重载函数:在两个对象都已经存在的情况下,将一个对象赋值给另一个对象

赋值运算符不可重载为全局函数

  赋值运算符重载跟拷贝构造类似,如果不显式实现,编译器会生成一个默认的赋值运算符重载,此时用户再类外自己实现一个全局的赋值运算符重载,就和编译器在类中生成的默认赋值运算符重载冲突,故而赋值运算符只能是类的成员函数(其他运算符函数可以重载为全局函数)

《C++ Primer》第5版P500有言:
在这里插入图片描述

默认生成赋值运算符重载对于内置类型与自定义类型处理方式:

  1. 内置类型成员变量直接赋值的
  2. 自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值

  同样的,我们有个深拷贝和浅拷贝的问题,方式还是跟拷贝构造方式一样,当涉及到动态资源申请的时候深拷贝,否则浅拷贝即可

前置++和后置++的重载

  这两个妙就妙在一样就只有一个操作符,一个操作符在前一个在后

C++给出了它的解决方案:

//++d1
Date& operator++()
{
	_day += 1;
	return *this;
}

//d1++
Date operator++(int)
{
	Date temp(*this);
	_day += 1;
	return temp;		
}

请注意,后置++重载函数中的参数int没有实际作用,只是为了与前置++构成函数重载,以便区分

二、const修饰成员函数

  将const修饰的 “成员函数” 称之为 const 成员函数,const修饰类成员函数,实际修饰改成员隐含的 this 指针,表明在该成员函数中不能对类的任何成员进行修改,如图:
在这里插入图片描述
在讲解具体的实用场景前,我们还可以先来看看这四个问题,答案和解释我都会相应给出:

  1. const对象可以调用非const成员函数吗?
  2. 非const对象可以调用const成员函数吗?
  3. const成员函数内可以调用其他的非const成员函数吗?
  4. 非const成员函数内可以调用其他的const成员函数吗

答案是:不可以、可以、不可以、可以

解释:
5. 非const成员函数,即成员函数的this指针没有被const所修饰,我们传入一个被const修饰的对象,用没有被const修饰的this指针进行接收,属于权限的放大,函数调用失败
6. const成员函数,即成员函数的this指针被const所修饰,我们传入一个没有被const修饰的对象,用被const修饰的this指针进行接收,属于权限的缩小,函数调用成功
7. 在一个被const所修饰的成员函数中调用其他没有被const所修饰的成员函数,也就是将一个被const修饰的this指针的值赋值给一个没有被const修饰的this指针,属于权限的放大,函数调用失败
8. 在一个没有被const所修饰的成员函数中调用其他被const所修饰的成员函数,也就是将一个没有被const修饰的this指针的值赋值给一个被const修饰的this指针,属于权限的缩小,函数调用成功

权限可以平移,也可以缩小,但是不可以放大

好,我们接下来来看以下代码:

// Print()成员函数没有被const修饰
int main()
{
	Date d1(2024, 9, 22);
	d1.Print(); // right,权限平移

	const Date d2(2024, 9, 22);
	d2.Print(); // err,权限放大

	return 0;
}

  但是并非所有函数都需要加上 const 修饰的!如果对成员变量进行读写访问的函数,不能加上 const ,另外,const修饰成员函数是修饰this指针的,那么 流插入>> 与 流提取<< 不是在类中实现,没有隐含的this指针,不能使用 const 修饰

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

  这两个默认成员函数一般不用重新定义,编译器会默认生成的,无需你多虑

class Date
{
public:
	Date* operator&()
	{
		return this;
	}
 
	const Date* operator&() const
	{
		return this;
	}
private:
	int _year; 
	int _month; 
	int _day; 
};

四、日期类的实现

 学完了这6个默认成员函数,我们来写个日期类巩固一下吧:

class Date
{
public:
	// 构造函数
	Date(int year = 1900, int month = 1, int day = 1);
	// 打印函数
	void Print() const;
	// 日期+=天数
	Date& operator+=(int day);
	// 日期+天数
	Date operator+(int day) const;
	// 日期-=天数
	Date& operator-=(int day);
	// 日期-天数
	Date operator-(int day) const;
	// 前置++
	Date& operator++();
	// 后置++
	Date operator++(int);
	// 前置--
	Date& operator--();
	// 后置--
	Date operator--(int);
	
	// 日期的大小关系比较
	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;
	
	// 日期-日期
	int operator-(const Date& d) const;

	// 析构,拷贝构造,赋值重载可以不写,使用默认生成的即可

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

构造函数

// 获取某年某月的天数
inline int GetMonthDay(int year, int month)
{
	// 数组存储平年每个月的天数
	static int dayArray[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
	int day = dayArray[month];
	if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
	{
		//闰年2月的天数
		day = 29;
	}
	return day;
}
// 构造函数
Date::Date(int year, int month, int day)
{
	// 检查日期的合法性
	if (year >= 0
	&& month >= 1 && month <= 12
	&& day >= 1 && day <= GetMonthDay(year, month))
	{
		_year = year;
		_month = month;
		_day = day;
	}
	else
	{
		// 严格来说抛异常更好
		cout << "非法日期" << endl;
		cout << year << "年" << month << "月" << day << "日" << endl;
	}
}

其中,我们注意一下这个GetMonthDay函数:

  1. 该函数可能被多次调用,所以我们最好将其设置为内联函数
  2. 函数中存储每月天数的数组最好是用static修饰,存储在静态区,避免每次调用该函数都需要重新开辟数组
  3. 逻辑与应该先判断 month == 2 是否为真,因为当不是2月的时候我们不必判断是不是闰年,短路判断

日期 += 天数

  因为出了作用域对象还存在,于是我们用引用返回
逻辑如下:
 1.若日已满,则日减去当前月的天数,月加一。
 2.若月已满,则将年加一,月置为1

// 日期 += 天数
Date& Date::operator+=(int day)
{
	if (day<0)
	{
		// 复用operator-=
		*this -= -day;
	}
	else
	{
		_day += day;
		// 日期不合法,通过不断调整,直到最后日期合法为止
		while (_day > GetMonthDay(_year, _month))
		{
			_day -= GetMonthDay(_year, _month);
			_month++;
			if (_month > 12)
			{
				_year++;
				_month = 1;
			}
		}
	}
	return *this;
}

日期 + 天数

  因为返回对象的值不变,但我们要返回变化后的值,于是就可以通过复用+=、创建临时变量tmp来解决,因为tmp出了作用域就销毁,于是我们用传值返回

// 日期 + 天数
Date Date::operator+(int day) const
{
	Date tmp(*this);// 拷贝构造tmp,用于返回
	// 复用operator+=
	tmp += day;

	return tmp;
}

日期 -= 天数

逻辑如下:
 1.若日为负数,则月减一。
 2.若月为0,则年减一,月置为12。
 3.日加上当前月的天数

// 日期 -= 天数
Date& Date::operator-=(int day)
{
	if (day < 0)
	{
		// 复用operator+=
		*this += -day;
	}
	else
	{
		_day -= day;
		// 日期不合法,通过不断调整,直到最后日期合法为止
		while (_day <= 0)
		{
			_month--;
			if (_month == 0)
			{
				_year--;
				_month = 12;
			}
			_day += GetMonthDay(_year, _month);
		}
	}
	return *this;
}

日期 - 天数

 跟日期 + 天数类似,也是复用

// 日期-天数
Date Date::operator-(int day) const
{
	Date tmp(*this);// 拷贝构造tmp,用于返回
	// 复用operator-=
	tmp -= day;
	return tmp;
}

日期类的大小比较

 这里,我们将充分发挥复用的智慧!

日期类 > 日期类

逻辑:年大则大,月大则大,年月相等比日

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)
		{
			return _day > d._day;
		}
	}
	return false;
}

日期类 == 日期类

逻辑:年月日均相等即为真

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

日期类 >= 日期类

逻辑:复用前面两个

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);
}

日期类 - 日期类

 其实也就是算两个日期之差,它还是有点意义的

试想一下,假如你未来结婚,结婚到一半,新娘子问你我们几年几月几日遇见的?
你早有准备,一下就回答上来
突然,新娘子还不死心,问你遇见当天离今天一共经历多少天?
你就可以说:“不急,我先跑个程序”
这就是日期类 - 日期类的一个实际场景运用

有两种思路,请听我细细道来:

 方法一:所谓日期 - 日期,即计算传入的两个日期相差的天数。我们只需要让较小的日期的天数一直加一,直到最后和较大的日期相等即可,这个过程中较小日期所加的总天数便是这两个日期之间差值的绝对值。若是第一个日期大于第二个日期,则返回这个差值的正值,若第一个日期小于第二个日期,则返回这个差值的负值,这很容易,设置一个判别变量 flag 即可

// 日期-日期
int Date::operator-(const Date& d) const
{
	Date max = *this;// 假设第一个日期较大
	Date min = d;// 假设第二个日期较小
	int flag = 1;// 此时结果应该为正值
	
	if (*this < d)
	{
		// 假设错误,更正
		max = d;
		min = *this;
		flag = -1;// 此时结果应该为负值
	}
	
	int n = 0;// 记录所加的总天数
	while (min != max)
	{
		min++;// 较小的日期++
		n++;// 总天数++
	}
	
	return n*flag;
}

 方法二:所谓“年、月、日”,不过也是一种进位的方式,那我们可以全把数堆给“日”这个位,先将年等同,再将月等同,最后直接将两个日期的“日”位相减即可,只需要注意返回的是正值还是负值

int Date::operator-(const Date& d)
{
	Date greD = (*this) > d ? *this : d;
	Date smlD = (*this) < d ? *this : d;

	while (greD._year > smlD._year) {
		if (isLeapYear(greD._year - 1)) greD._day += 366;
		else greD._day += 365;
		
		greD._year -= 1;
	}

	while (greD._month > smlD._month) {
		greD._month -= 1;
		greD._day += GetMonthDay(greD._year, greD._month);
	}

	while (greD._month < smlD._month) {
		greD._month += 1;
		greD._day -= GetMonthDay(greD._year, greD._month);
	}
	int ret = greD._day - smlD._day;

	return *this > d ? ret : -ret;
}

五、流插入流提取运算符重载

  这个比较困难,有一些不懂的概念可以暂且放一下

  其实,我们平时说cout、cin能自动识别类型,本质上就是因为重载,cout属于ostream类,cin属于istream类
在这里插入图片描述
  假如我们 重载运算符<< 为成员函数,隐含的 this 指针占用第一个参数的位置,Date必须是左操作数,使用时候d1<<cout 是不符合我们的习惯的

  于是,我们要将其重载为全局函数,并且把ostream& out放在第一个位置!但是又引出了另一个问题:类外不能访问类中的私有成员,如果将私有权限放开,就缺乏安全性,对此C++中有友元,接下来我们会涉及到,这里就使用下,虽然这个全局函数不在类中,但是可以访问私有成员函数

//友元,告诉该类这两个全局函数是我们的朋友,允许使用私有成员(在类中)
	friend ostream& operator<<(ostream& out, const Date& d);
	friend istream& operator>>(istream& in, Date& d);

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

总结

  哈哈,这个中篇终于结束了,想不到吧,学Cpp的第一个大内容就如此困难!
  还有个下篇呢,继续加油吧!

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

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

相关文章

嵌入式系统stm32cube本地安装出现的问题

stm32cube在线安装很慢&#xff0c;本地安装中出现的一个bug stm32cube_fw_f4_v1281安装成功之后&#xff0c;如果想安装stm32cube_fw_f4_v1281会提示stm32cube_fw_f4_v1280未安装。 如果先安装stm32cube_fw_f4_v1280之后&#xff0c;再安装stm32cube_fw_f4_v1281还会提示这个…

Python模拟鼠标轨迹[Python]

一.鼠标轨迹模拟简介 传统的鼠标轨迹模拟依赖于简单的数学模型&#xff0c;如直线或曲线路径。然而&#xff0c;这种方法难以捕捉到人类操作的复杂性和多样性。AI大模型的出现&#xff0c;能够通过深度学习技术&#xff0c;学习并模拟更自然的鼠标移动行为。 二.鼠标轨迹算法实…

C#如何把写好的类编译成dll文件

1 新建一个类库项目 2 直接改写这个Class1.cs文件 3 记得要添加Windows.Forms引用 4 我直接把在别的项目中做好的cs文件搞到这里来&#xff0c;连文件名也改了&#xff08;FilesDirectory.cs&#xff09;&#xff0c;这里using System.Windows.Forms不会报错&#xff0c;因为前…

go项目多环境配置

1.java项目配置加载最佳实践 在 Spring Boot 项目中&#xff0c;配置文件的加载和管理是开发过程中不可或缺的一部分。Spring Boot 提供了一套灵活且强大的机制来加载配置文件&#xff0c;使得开发者能够根据不同的环境和需求轻松地管理配置。当多个位置存在相同的配置文件时&…

Python语法进阶之路

一、Python基础 1.1 注释 定义和作用 对代码解释说明&#xff0c;增强可读性 单行注释 # 多行注释 """ 这是一个多行注释 """ 1.2 变量及变量类型 定义和作用 计算机目的是计算&#xff0c;编程是为了更方便计算&#xff0c;计算对象就是…

vue循环渲染动态展示内容案例(“更多”按钮功能)

当我们在网页浏览时&#xff0c;常常会有以下情况&#xff1a;要展示的内容太多&#xff0c;但展示空间有限&#xff0c;比如我们要在页面的一部分空间中展示较多的内容放不下&#xff0c;通常会有两种解决方式&#xff1a;分页&#xff0c;“更多”按钮。 今天我们的案例用于…

mybatis 配置文件完成增删改查(二):根据条件查询一个

文章目录 参数占位符#{}:会将其替换为&#xff1f; ——为了防止sql注入${}:会将其替换为实际接收到的数据&#xff0c;拼sql ——无法防止sql注入 查询一个sql特殊字符的处理 参数占位符 #{}:会将其替换为&#xff1f; ——为了防止sql注入 ${}:会将其替换为实际接收到的数据…

Java继承教程!(o|o)

Java 继承 Java面向对象设计 - Java继承 子类可以从超类继承。超类也称为基类或父类。子类也称为派生类或子类。 从另一个类继承一个类非常简单。我们在子类的类声明中使用关键字extends&#xff0c;后跟超类名称。 Java不支持多重继承的实现。 Java中的类不能有多个超类。…

Linux-gcc/g++

系列文章目录 C语言中的编译和链接 文章目录 系列文章目录一、编译过程gcc如何完成过程在这里涉及到一个重要的概念:函数库 二、动态库、静态库2.1 函数库一般分为静态库和动态库两种。 三、gcc选项gcc选项记忆 一、编译过程 具体过程在这一片c语言文章中讲解过:C语言中的编…

shardingjdbc分库分表原理

一 Mysql的瓶颈 二 解决方案 三 hash环算法 四 雪花算法

CCF csp认证 小白必看

c支持到C17(还是更高?)&#xff1b;所以学一些封装好的函数功能是必要的---比如STL里的函数&#xff1b; 因为可携带纸质资料&#xff0c;建议打印带入&#xff0c;需要时可翻阅。 【题目概述:】 0-devc环境配置 配置好你常用的编译版本&#xff1a; 想要调试记得开启下选…

分布式系统的CAP原理

CAP 理论的起源 CAP 理论起源于 2000 年&#xff0c;由加州大学伯克利分校的 Eric Brewer 教授在分布式计算原理研讨会&#xff08;PODC&#xff09;上提出&#xff0c;因此 CAP 定理又被称作布鲁尔定理&#xff08;Brewer’s Theorem&#xff09;。2002 年&#xff0c;麻省理…

「OC」引用计数(一)

iOS学习 前言自动引用计数引用计数引用计数的思考方式自己生成的对象&#xff0c;自己持有非自己生成的对象&#xff0c;自己也能持有不再需要自己持有的对象时释放无法释放非自己持有的对象 总结 前言 在学习oc时对引用计数略有了解&#xff0c;现在进行系统的学习总结。 自动…

力扣 无重复字符的最长子串

无重复字符的最长子串 https://leetcode.cn/problems/longest-substring-without-repeating-characters/description/ 题目描述 题目分析 寻找无重复字符子串&#xff0c;首先要求是子串&#xff0c;然后是无重复 子串可以用滑动窗口确定 问题在于如何确定无重复 如果用暴力枚…

Java笔试面试题AI答之设计模式(5)

文章目录 21. 简述Java什么是适配器模式 ?适配器模式的主要组成部分包括&#xff1a;适配器模式的实现方式主要有两种&#xff1a;适配器模式的优点&#xff1a;适配器模式的缺点&#xff1a;示例说明&#xff1a; 22. 请用Java代码实现适配器模式的案例 &#xff1f; 21. 简述…

01 基础request

目录 类 WxRequest 的定义 静态属性 default 构造函数 constructor 方法 request HTTP 方法封装 创建 WxRequest 实例并导出 完整代码&#xff1a; 类 WxRequest 的定义 创建一个 WxRequest 类包含一个静态属性 default 和几个方法&#xff0c;用于处理网络请求。 静态…

Kotlin编程全攻略:从基础到实战项目的系统学习资料

Kotlin作为一种现代、简洁的编程语言&#xff0c;正逐渐成为Android开发的新宠。本文将为您介绍一套全面的Kotlin学习资料&#xff0c;包括学习大纲、PDF文档、源代码以及配套视频教程&#xff0c;帮助您从Kotlin的基础语法到实战项目开发&#xff0c;系统地提升您的编程技能。…

jetlinks物联网平台学习2(加盐算法登陆)

加盐算法 加盐算法加密验证密码是否正确 对于传统的MD5加密&#xff0c;比更传统的直接保存账号密码稍微安全一点。 md5加密是一种hash算法 比如对于123456来说&#xff0c;md5算法结果一定是e10adc3949ba59abbe56e057f20f883e 这个结果是固定的。于是有的人准备一张彩虹表 预先…

vscode 配置django

创建运行环境 使用pip安装Django&#xff1a;pip install django。 创建一个新的Django项目&#xff1a;django-admin startproject myproject。 打开VSCode&#xff0c;并在项目文件夹中打开终端。 在VSCode中安装Python扩展&#xff08;如果尚未安装&#xff09;。 在项…

SpringCloud-07 GateWay01 网关技术

Spring Cloud Gateway组件的核心是一系列的过滤器&#xff0c;通过这些过滤器可以将客户端发送的请求转发(路由)到对应的微服务。 Spring Cloud Gateway是加在整个微服务最前沿的防火墙和代理器&#xff0c;隐藏微服务结点IP端口信息&#xff0c;从而加强安全保护。Spring Clou…