【C++】类与对象(三)

news2024/11/17 14:19:09

前言

本章我们接替前一章继续深入理解类的默认成员函数,赋值重载取地址重载,及const取地址操作符重载

但是在讲剩下的三个默认成员函数之前,我们要先来了解运算符重载,因为赋值重载,取地址重载,及const取地址操作符重载其实是属于运算符重载的一部分。

类与对象(三)

  • 一、运算符重载
    • 1、运算符重载的概念
    • 2、运算符重载的注意事项
  • 二、运算符重载的特例
    • 1、前置++和后置++类型
    • 2、流插入<< 流提取>>运算符
  • 四、赋值运算符重载(默认成员函数)
    • 1、引入
    • 2、特性
      • 1. 用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝。
      • 2. 赋值运算符重载格式:
      • 3. 赋值运算符只能重载成类的成员函数不能重载成全局函数
      • 4. 如果类中未涉及到资源管理,赋值运算符是否实现都可以;一旦涉及到资源管理则必须要实现。
  • 五、取地址及const取地址操作符重载
    • 1、取地址操作符重载(默认成员函数)
      • 取地址重载的手动实现
    • 2、const取地址操作符重载(默认成员函数)
      • const取地址重载手动实现


一、运算符重载

1、运算符重载的概念

对于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;
	}
	//给一个给日期加num天,不修改原始值
	Date Add(int num)
	{
		//......
	}
	//给一个日期加num天,并修改原始值
	Date AddEqual(int num)
	{
		//.....
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	int a = 10;
	a + 10;
	a += 10;
	Date d1;
	d1.Add(10);
	//d1+10;    //想写成这样,这样更直观方便,可是编译器不允许啊啊啊
	d1.AddEqual(10);
	//d1+=10;   //想写成这样,这样更直观方便,可是编译器不允许啊啊啊
	return 0;
}

C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。

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

函数原型:返回值类型 operator操作符(参数列表)

只看定义不太好理解运算符重载,我们还是直接先看代码,结合代码边分析边理解定义与注意要点。

// 全局的operator==
#include<iostream>
using namespace std;
class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
//private:
	int _year;
	int _month;
	int _day;
};
// 这里会发现:运算符重载成全局的 就需要成员变量是公有的,不然下面的函数无法访问到成员变量,
// 那么问题来了,封装性如何保证?
//这点我们现在还没有办法解决,所以我们先暂时将成员设定为公有。
//还有一种办法就是把它写进类中,变成成员函数。(暂时不用此种方法)

//判断两个对象是否相同
bool operator==(const Date& d1, const Date& d2)
{
	return d1._year == d2._year
		&& d1._month == d2._month
		&& d1._day == d2._day;
}

void Test()
{
	Date d1(2023, 2, 12);
	Date d2(2023, 2, 12);
	cout << operator==(d1, d2) << endl;//判断两个对象是否相同,第一种使用方法,直接调用函数
	cout << (d1 == d2) << endl;//判断两个对象是否相同,第二种使用方法,使用重载后的运算符
	//此处必须加括号,运算符优先级:<< 大于 ==
}

相信仔细看完这个代码后你已经对运算符重载有了一定的了解,就是大概相当于自定义类型的运算符其实是一个我们手动写函数,但是呢经过运算符重载以后我们可以像使用内置类型运算符那样去使用函数。

2、运算符重载的注意事项

  • 不能通过连接其他符号(C++中不存在的运算符)来创建新的操作符:比如operator@
  • 重载操作符必须有一个类类型参数(因为运算符重载主要是为了让自定义类型能够像内置类型那样去使用运算符)
  • 用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不 能改变其含义(因为运算符重载主要是为了让自定义类型能够像内置类型那样去使用运算符,内置类型不需要运算符重载)
  • 作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐 藏的this
  • .* :: sizeof ?: . 注意以上5个运算符不能重载。这个经常在笔试选择题中出现。

二、运算符重载的特例

1、前置++和后置++类型

经过上面的运算符重载的讲解相信你对于Date类中的一些其他运算符也能写出它的运算符重载如:

class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	Date& operator+(int num)
	{
		//......
	}
	Date& operator-(Date& d)
	{
		//......
	}
	Date& operator+=(int num)
	{
		//......
	}
	//......
	//其实这么多运算符重载我们可以一一实现,也可以实现一到两个,然后让其他运算符重载
private:
	int _year;
	int _month;
	int _day;
};

但是我们在学习C语言时学习过 前置++,后置++,前置- -,后置- -, 对于这种运算符重载我们应该怎么做呢?
我们先写一下函数外部的参数列表:

//前置++
	Date& operator++()
	{

	}
//后置++
	Date operator++()
	{

	}

我们发现它们的函数外部参数列表一模一样,这样根本无法构成函数重载,我们也只能实现 前置++,后置++中的一个。
为了解决这个问题,我们C++给这种前置++,后置++,前置- -,后置- -,这种运算符重载时进行了特殊化处理,规则是:

  1. 前置++正常实现
  2. 后置++在运算符重载时多传一个int型参数(此参数只是为了占位,实现函数重载,不起其他作用,也不必真的传递参数)

(- -与以上规则类似)

所以正确实现我们应该这样实现:

//前置++
	Date& operator++()
	{
		*this += 1;//假设 +=我们已经运算符重载过了
		return this;
	}
//后置++
	Date operator++(int a)//形参名可以不写,直接写成 int,调用时也不需要传递参数
	{
		Date tmp(this); //会去调用拷贝构造 
		*this += 1; //假设 +=我们已经运算符重载过了
		return tmp;
	}

2、流插入<< 流提取>>运算符

在前面讲解运算符重载时我们说过,<<其实是移位运算符,但是呢在C++中被重载为了流插入运算符,那具体是怎么做的呢?我们现在学习了运算符重载已经可以去讨论这个问题了。

首先我们经常使用的coutcin,其实分别是一个ostream类型对象,一个是istream类型的对象,这两个类型又分别在<ostream><istream>两个C++标准库的std标准命名空间内,然后我们经常使用的C++标准库<iostream>又包含了<istream><ostream>头文件,所以我们使用cincout的时即要包含头文件<iostream>又要使用using namespeace std;将标准命名空间里面的内容展开到全局中。

在这里插入图片描述
我们再来看看流提取<<运算符重载
在这里插入图片描述

可以看到在C++对流提取<<运算符进行了许多运算符重载+函数重载,我们对于内置类型可以随意使用<<,但是自定义类型我们却没有办法使用,因为自定义类型是我们自定义的,C++无法提前预知我们要写什么自定义类型,然后给我们的自定义类型进行运算符重载,所以我们想让我们的自定义类型也能用流提取<<,必须我们手动实现自定义类型的<<的运算符重载。
在这里插入图片描述


我们先来看看第一种写法

//<< 运算符重载
#include<iostream>
using namespace std;
class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	ostream& operator<< (ostream&out)
	{
		out << _year << "年" << _month << "月" << _day << "日" << endl;
		return out;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1;
	int a = 10;
	cout << a << endl;//C++对自定义类型已经实现了 << 的运算符重载
	cout << d1;  
	return 0;
}

在这里插入图片描述
编译失败了,我们仔细检查检查,会发现是67行我们写反了!应该写成

d1 << cout;           //第一种写法
d1.operator<<(cout);  //第二种写法

因为运算符重载时,第一个参数是左操作数,第二个操作数是右操作数(注意,第一个参数是隐藏的this指针)

写正确后我们运行一下:

在这里插入图片描述
没有问题,但是这样写也太变态了,违法我们的使用直觉使用啊,直觉告诉我们,我们应该这样使用:

cout << d1;

那么我们就应该把这个流插入<<重载定义到函数外面,因为定义在类的内部默认传递的第一个参数就是this指针,我们永远达不到目的。
于是我们定义在外面:

#include<iostream>
using namespace std;
class Date
{
	friend ostream& operator<<(ostream& out, Date& d);//友元,允许我们在类外部使用成员变量。
public:
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	
private:
	int _year;
	int _month;
	int _day;
};

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

int main()
{
	Date d1;
	int a = 10;
	cout << a << endl;//C++对自定义类型已经实现了 << 的运算符重载
	cout << d1;
	return 0;
}

还又一个问题我们写<<运算符重载时为什么要用引用呢?
在这里插入图片描述
注意:<<是左结合性!
返回值用引用了我们就可以实现连续多个自定义类型打印了!

//假如d1 d2 d3 都是Date类型
cout << d1 << d2 << d3 << endl;

四、赋值运算符重载(默认成员函数)

1、引入

我们首先来看一个使用场景,我们想要把一个已经初始化的自定义类型的数据赋值给另一个已经初始化的自定义类型(不是对象初始化时赋值,对象初始化时赋值用的是拷贝构造)该怎么办?
看看下面的代码:

//赋值重载
#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 << "月" << _month << "日" << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1;
	Date d2 = d1;//或者Date d2(d1)  会调用默认生成的拷贝构造,对象初始化时赋值用的是拷贝构造
	Date d3;
	d3 = d1;//我们没有实现Date类的运算符 = 的赋值重载,所以会调用默认生成的赋值重载
	        //最后d3里面的数据与d1一样
}

2、特性

1. 用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝。

注意:内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值(=)运算符重载完成赋值。
实例代码:
如上面的代码

2. 赋值运算符重载格式:

参数类型:const T&,传递引用可以提高传参效率
返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值检测是否自己给自己赋值
返回*this :要符合连续赋值的含义

#include<iostream>
using namespace std;
class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	Date(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
	//自己写的 赋值重载
	Date& operator=(const Date& d)
	{
		if (this != &d)
		{
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}
		return *this;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1(2023,2,12);
	Date d2;
	d2 = d1;
	return 0;
}

在这里插入图片描述
在这里插入图片描述

3. 赋值运算符只能重载成类的成员函数不能重载成全局函数

#include<iostream>
using namespace std;
class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	int _year;
	int _month;
	int _day;
};
// 赋值运算符重载成全局函数,注意重载成全局函数时没有this指针了,需要给两个参数
Date& operator=(Date& left, const Date& right)
{
	if (&left != &right)
	{
		left._year = right._year;
		left._month = right._month;
		left._day = right._day;
	}
	return left;
}
// 编译失败:
// error C2801: “operator =”必须是非静态成员

在这里插入图片描述


原因:赋值运算符如果不显式实现,编译器会生成一个默认的。
此时用户再在类外自己实现一个全局的赋值运算符重载,就和编译器在类中生成的默认赋值运算符重载冲突了,故赋值运算符重载只能是类的成员函数

在这里插入图片描述

4. 如果类中未涉及到资源管理,赋值运算符是否实现都可以;一旦涉及到资源管理则必须要实现。

和拷贝构造函数一样我们继续思考:既然编译器生成的默认赋值运算符重载函数已经可以完成字节序的值拷贝了,对于内置类型还需要自己实现吗?
和拷贝构造一样,特性4也是我们写与不写复制重载函数的判断条件!
例如:

// 这里会发现下面的程序会崩溃掉,编译器生成的是浅拷贝,导致我们析构了两次空间,
//这里就需要我们以后讲的深拷贝去解决。
#include<iostream>
using namespace std;
typedef int DataType;
class Stack
{
public:
	Stack(size_t capacity = 10)
	{
		_array = (DataType*)malloc(capacity * sizeof(DataType));
		if (nullptr == _array)
		{
			perror("malloc申请空间失败");
			return;
		}
		_size = 0;
		_capacity = capacity;
	}
	void Push(const DataType& data)
	{
		// CheckCapacity();
		_array[_size] = data;
		_size++;
	}
	~Stack()
	{
		if (_array)
		{
			free(_array);
			_array = nullptr;
			_capacity = 0;
			_size = 0;
		}
	}
private:
	DataType* _array;
	size_t _size;
	size_t _capacity;
};
int main()
{
	Stack s1;
	s1.Push(1);
	s1.Push(2);
	s1.Push(3);
	s1.Push(4);
	Stack s2;
	s2 = s1;
	return 0;
}

在这里插入图片描述
到这里我们就把六个默认成员函数中的第四个:复制重载给讲完了。
复制重载其实是运算符重载的一部分!

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

1、取地址操作符重载(默认成员函数)

我们还是先看代码再思考:

#include<iostream>
using namespace std;
class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}

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

int main()
{
	Date d1;
	cout << &d1 << endl;
}

在这里插入图片描述
结果符合我们的预期,你可能觉得没有什么值得思考的点。
但是我们说过:对于自定义类型我们不能对他们像对内置类型那样使用运算符,但是我们对Date类的对象 d1 使用了取地址运算符&,而我们并没有实现&的运算符重载,结果我们却可以使用&,而且结果很对。为什么呢?

这是因为第五个默认成员函数:取地址操作符重载,即我们不写,编译器会帮我们自动生成,它的作用就是帮我们实现自定义类型对象的取地址。

取地址重载的手动实现

通常情况下我们一般自己不写此函数,让编译器自动生成。那假设我们自己实现此函数该怎么办呢?

实现代码如下:

//取地址重载函数
#include<iostream>
using namespace std;
class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	//取地址重载
	Date* operator&()
	{
		return this;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1;
	cout << &d1 << endl;
}

在这里插入图片描述

2、const取地址操作符重载(默认成员函数)

我们定义对象时一般都不会加const,那我们如果给对象加const会发生什么?
那我们再看一段代码:

#include<iostream>
using namespace std;
class Date
{
public:
	Date(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void Print()
	{
		cout << "Print()" << endl;
		cout << "year:" << _year << endl;
		cout << "month:" << _month << endl;
		cout << "day:" << _day << endl << endl;
	}
private:
	int _year; // 年
	int _month; // 月
	int _day; // 日
};
int main()
{
	Date d1(2022, 1, 13);
	d1.Print();
	const Date d2(2022, 1, 13);
	d2.Print();
	return 0;
}

我们发现无法编译通过
在这里插入图片描述
为什么给对象加了const后我们调用函数就失败了呢?按照加const报错的常见原因,不难想应该是权限被放大了。

还记得this指针的类型是什么吗?答案是:* const类型。这里应该是Date * const
我们用const修饰的对象取地址后应该是什么类型?答案是:const *。这里应该是const Date*
两个类型不匹配,const修饰对象后内容不能被更改,所以我们的this指针要改变类型,在*前加一个const
在这里插入图片描述

但是呢 this指针是编译器传递的,我们无法加const ,这该怎么办呢?
这里C++编译器又做了特殊化处理我们需要加const在函数括号后面,才能对this指针进行修饰

正确代码:

#include<iostream>
using namespace std;
class Date
{
public:
	Date(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void Print() const
	{
		cout << "Print()const" << endl;
		cout << "year:" << _year << endl;
		cout << "month:" << _month << endl;
		cout << "day:" << _day << endl << endl;
	}
private:
	int _year; // 年
	int _month; // 月
	int _day; // 日
};
int main()
{
	Date d1(2022, 1, 13);
	d1.Print();
	const Date d2(2022, 1, 13);
	d2.Print();
	return 0;
}

在这里插入图片描述

在这里插入图片描述
将const修饰的“成员函数”称之为const成员函数,const修饰类成员函数,实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改。

请思考下面的几个问题:

  1. const对象可以调用非const成员函数吗?
    答案:不可以,传递this指针时权限会放大
  2. 非const对象可以调用const成员函数吗?
    答案:可以,传递this指针时权限缩小
  3. const成员函数内可以调用其它的非const成员函数吗?
    答案:不可以,传递this指针时权限会放大
  4. 非const成员函数内可以调用其它的const成员函数吗?
    答案:可以,传递this指针时权限缩小

const取地址重载手动实现

同理在前面的代码中我们取const类型的地址时没有对&进行重载,但我们却可以使用,同样是因为编译器自动帮我们实现了const取地址重载

注意两个不太一样,两个函数构成函数重载!

取地址操作符重载

Date* operator&()             //对非 const 对象取地址

const取地址重载

const Date* operator&()const  //对 const 对象取地址

手动实现:

//const取地址重载函数
#include<iostream>
using namespace std;
class Date
{
public:
	Date(int year=0, int month=0, int day=0)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void Print() const
	{
		cout << "Print()const" << endl;
		cout << "year:" << _year << endl;
		cout << "month:" << _month << endl;
		cout << "day:" << _day << endl << endl;
	}
	const Date* operator&()const //返回值const Date * 是为了与this 指针保持一致
	{
		return this;
	}
private:
	int _year; // 年
	int _month; // 月
	int _day; // 日
};
int main()
{
	const Date d1;
	cout << &d1 << endl;
	return 0;
}

在这里插入图片描述

在这里插入图片描述
这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可,只有特殊情况,才需要重载,比如想让别人获取到指定的内容

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

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

相关文章

Compose-Navigation简单案例上手

Navigation 快速上手 下面案例简要展示使用 Compose 版本的 Navigation 库来实现两个页面之间的跳转 这是完整的结构&#xff08;忽略掉红线划过的那个包&#xff09; 安装适用于 kotlin 的 navigation 依赖 dependencies {implementation("androidx.navigation:navigati…

兼职任务平台收集(一)分享给有需要的朋友们

互联网时代&#xff0c;给人们带来了很大的便利。信息交流、生活缴费、足不出户购物、便捷出行、线上医疗、线上教育等等很多。可以说&#xff0c;网络的时代会一直存在着。很多人也在互联网上赚到了第一桶金&#xff0c;这跟他们的努力和付出是息息相关的。所谓一份耕耘&#…

使用kubeadm部署k8s1.24.0版本,遇到的坑总结

使用kubeadm部署k8s1.24.0版本&#xff0c;遇到的坑总结环境安装遇到的问题环境 操作系统&#xff1a;centos7 内核&#xff1a;5.4.231-1.el7.elrepo.x86_64 kubeadm&#xff1a;1.24.0 kubelet&#xff1a;1.24.0 kubectl&#xff1a;1.24.0 cri&#xff1a;docker cni&…

nginx rewrite 规则

生效位置 rewrite 可以写在 server 、 location、 if 配置段内 格式 rewrite regex replacement [flag] regex是匹配的正则表达式。 只会处理$request_uri部分&#xff0c;不会匹配$host replacement 是跳转的URI。 可以以http:// 或者https:// 开头&#xff0c; 也…

自适应多因素认证:构建不可破解的企业安全防线|身份云研究院

打开本文意味着你理解信息安全的重要性&#xff0c;并且希望获取行业最佳实践来保护你所在组织的信息安全。本文将带你了解多因素认证&#xff08;MFA&#xff1a;Multi-Factor-Authentication&#xff09;对于企业信息安全的重要性以及实施方法。 多因素认证&#xff08;MFA&…

尚医通(十五)医院排班管理

目录一、医院排班管理需求1、页面效果2、接口分析二、科室列表&#xff08;接口&#xff09;1、添加service接口和实现2、添加DepartmentController方法三、科室列表&#xff08;前端&#xff09;1、添加隐藏路由2、封装api方法3、添加/views/hosp/schedule.vue组件四、排班日期…

torch相比于numpy都干了什么——torch入门

Torch已深度学习框架被熟知&#xff0c;但它首先是作为Numpy的存在。我们首先比较一下Torch和Numpy有什么不同&#xff0c;为什么可以实现深度学习。 从数据结构看起。Numpy的强大之处就在于array的数据结构&#xff0c;它是多维数组&#xff0c;要求所有元素是相同类型的&…

人与人之间赚钱的差距在哪里呢?体现在这几个因素中

同样生而为人&#xff0c;同样接受九年制义务教育的熏陶&#xff0c;但最终赚钱能力却千差万别&#xff0c;因此也就形成了我们所谓的圈层&#xff0c;阶层&#xff0c;穷人和富人。 一个人的赚钱能力跟什么有关&#xff1f;资源技能、学历、认知&#xff0c;这些都会决定一个人…

搞清楚动态库和静态库的区别

什么是库文件 一般来说&#xff0c;一个程序&#xff0c;通常都会包含目标文件和若干个库文件。经过汇编得到的目标文件再经过和库文件的链接&#xff0c;就能构成可执行文件。库文件像是一个代码仓库或代码组件的集合&#xff0c;为目标文件提供可直接使用的变量、函数、类等…

visual studio 改变界面语言

在使用visual studio 2019 时&#xff0c;开始是英文界面&#xff0c;后面变成了中文界面。但是看视频教学时有的是英文界面&#xff0c;我就想回到英文界面&#xff0c;所以有切换界面语言的需要。其实操作很简单&#xff1a;工具-> 选项 打开界面在界面里选择环境&#xf…

axios中的resolvePromise为什么影响promise状态

axios的取消请求意思很简单&#xff0c;就是在发送请求后不久停止发送请求 本文探讨的是v0.22.0之前的CancelToken API&#xff0c;因为在阅读源码交流的时候发现很多朋友不理解为什么CancelToken中的resolvePromise会影响到实例对象身上的promise状态 即下图所示代码&#xf…

为乡村振兴塑形铸魂,VR全景助力美丽乡村建设

民族要复兴&#xff0c;乡村必振兴&#xff0c;文旅部一直推动乡村文化产业和乡村旅游融合发展&#xff0c;大力推进乡村文化数字化&#xff0c;为乡村文化振兴注入新动能。为了更好的给乡村振兴塑形铸魂&#xff0c;VR智慧乡村助力数字化乡村建设发展&#xff0c;利用VR全景展…

CMD SET % 字符串截取

:: 使用 CSDN Cobol 格式化风格。:: *. 百分号 (%) :: (1) % 作为变量引导符&#xff0c;有几种用途&#xff1a;在命令行窗口中&#xff0c;用 1 个 % 引号变量; 在批处理文件中&#xff0c;用 2 个 % 引号变量。[1] 两个 % 夹着一个变量名称&#xff0c;表示取&#xff08;扩…

HashMap如何避免内存泄露问题

HashMap对于Java开发人员来说&#xff0c;应该是一种非常非常熟悉的数据结构了&#xff0c;应用场景相当广泛。 本文重点不在于介绍如何使用HashMap&#xff0c;而是关注在使用HashMap过程中&#xff0c;可能会导致内存泄露的情况&#xff0c;下面将以示例的形式展开具体介绍。…

【Java】properties 和 yml 的区别

文章目录properties和yml的区别① 定义和定位不同② 语法不同③ yml更好的配置多种数据类型④ yml可以跨语言⑤ 总结properties和yml的区别 这几天刚好看到Spring Boot当中有两种配置文件的方式&#xff0c;但是这两种配置方式有什么区别呢&#xff1f; properties和yml都是S…

hadoop考试应急

概述 四大特点&#xff1a;大量化、快速化、多元化、价值化 关键技术&#xff1a;采集、存储管理、处理分析、隐私和安全 计算模式&#xff1a;批处理、流、图、查询分析计算 Hadoop处理架构 了解就好 2007年&#xff0c;雅虎在Sunnyvale总部建立了M45——一个包含了4000…

Leetcode 每日一题 2341. 数组能形成多少数对

Halo&#xff0c;这里是Ppeua。平时主要更新C语言&#xff0c;C&#xff0c;数据结构算法......感兴趣就关注我吧&#xff01;你定不会失望。 &#x1f308;个人主页&#xff1a;主页链接 &#x1f308;算法专栏&#xff1a;专栏链接 我会一直往里填充内容哒&#xff01; &…

《Java并发编程之美》- 线程终止的方法

多线程并发编程之美 等待线程执行终止的 join 方法 执行的代码 public class MyThreadThree {public static void main(String[] args) throws InterruptedException {Thread thread_anew Thread(()->{try {Thread.sleep(1000);} catch (InterruptedException e) {e.prin…

信息系统项目管理师真题精选(三)

1、以下关于我国现阶段电子政务建设的叙述中&#xff0c;不正确的是&#xff1a;&#xff08; &#xff09;。A.我国电子政务建设一直坚持统一规划&#xff0c;加强领导&#xff0c;需求主导&#xff0c;突出重点的原则B.我国电子政务建设一直坚持整合资源&#xff0c;拉动产业…

静态代理和动态代理的区别以及实现过程

前言 代理模式是一种设计模式&#xff0c;能够使得在不修改源目标的前提下&#xff0c;额外扩展源目标的功能。即通过访问源目标的代理类&#xff0c;再由代理类去访问源目标。这样一来&#xff0c;要扩展功能&#xff0c;就无需修改源目标的代码了。只需要在代理类上增加就可…