【C++】类与对象(三) 运算符重载 赋值重载 取地址及const取地址操作符重载

news2024/11/16 22:36:35

前言

本章我们接替前一章继续深入理解类的默认成员函数,赋值重载取地址重载,及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/349394.html

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

相关文章

10分钟学会python对接【OpenAI API篇】

今天学习 OpenAI API&#xff0c;你将能够访问 OpenAI 的强大模型&#xff0c;例如用于自然语言的 GPT-3、用于将自然语言翻译为代码的 Codex 以及用于创建和编辑原始图像的 DALL-E。 首先获取生成 API 密钥 在我们开始使用 OpenAI API 之前&#xff0c;我们需要登录我们的 Op…

Linux 定时任务调度(crontab)整理,太实用了!

crontab命令用于设置周期性被执行的指令。该命令从标准输入设备读取指令&#xff0c;并将其存放于“crontab”文件中&#xff0c;以供之后读取和执行。可以使用crontab定时处理离线任务&#xff0c;比如每天凌晨2点更新数据等&#xff0c;经常用于系统任务调度。服务启动和关闭…

AWS攻略——创建VPC

文章目录创建一个可以外网访问的VPCCIDR主路由表DestinationTarget主网络ACL入站规则出站规则子网创建EC2测试连接创建互联网网关&#xff08;IGW&#xff09;编辑路由表参考资料在 《AWS攻略——VPC初识》一文中&#xff0c;我们在AWS默认的VPC下部署了一台可以SSH访问的机器实…

WRAN翻译

基于小波的图像超分辨残差注意力网络 Wavelet-based residual attention network for image super-resolution 代码&#xff1a; https://github.com/xueshengke/WRANSR-keras 摘要&#xff1a; 图像超分辨率技术是图像处理和计算机视觉领域的一项基础技术。近年来&#xff0c…

【流辰信息技术】做好数据管理,赋能行业全速提升产业效能

在经济快速发展的当下&#xff0c;正是各行各业大展拳脚&#xff0c;全力以赴奔赴产能提升的好契机。做好企业&#xff0c;不仅要有一颗发展雄心&#xff0c;而且还要学会运用正确的技术和发展战略&#xff0c;推动企业向前进。流辰信息技术是低代码开发领域里的服务商&#xf…

自动化测试高频面试题(含答案)

Hello&#xff0c;你们的好朋友来了&#xff01;今天猜猜我给大家带来点啥干货呢&#xff1f;最近很多小伙伴出去面试的时候经常会被问到跟自动化测试相关的面试题。所以&#xff0c;今天特意给大家整理了一些经常被公司问到的自动化测试相关的面试题。停&#xff0c;咱先收藏起…

「团队管理」前端开发者如何规划并构建UCD的中长期前端开发能力与团队

文章目录 前言一、个人规划1.1 技能和知识的提升1.2 用户研究和用户体验1.3 团队协作能力1.4 项目管理和交付能力1.5 技术创新和开发效率二、构建UCD团队2.1 人才招聘和培养2.2 角色定义和分工2.3 团队文化和价值观前言 UCD(用户中心设计)是一种基于用户需求的设计方法论,将…

五千字总结一枚测试妹纸不平凡的2022

大家好&#xff0c;我是美团程序员&#xff0c;一个混过大厂&#xff0c;待过创业公司&#xff0c;爱给开发同学提Bug的测试妹纸一枚。2022年&#xff0c;是工作的第六年&#xff0c;也是具有突破性成长的一年&#xff0c;一直挺喜欢六这个数字&#xff0c;果然不负期望&#x…

C控制语句(if,switch,goto)

一.if 1.if循环语句格式 if(expression1) statement1 else if(expression2) statement2 else if(expression3) statement3 . . . else statement(n) else if 可以使用也可以不是用。 这里我们用一个例子进行讲解 2.if else 注意事项 If else if else之间只允许有一条语句&…

Shell - 随时启动 + 固定时间启动脚本

一.引言 有一个线上任务需要在每 10 min内的 5min 后执行&#xff0c;例如 5:10、15:10 ...、55: 10&#xff0c;正常情况下需要查看 Clock Time&#xff0c;待时间到达 5min 后手动启动&#xff0c;下面实现随时启动脚本&#xff0c;定时在 x5:10 点执行。 二.实现 A.固定 5…

【第0天】SQL快速入门-了解MySQL存储引擎(SQL 小虚竹)

回城传送–》《32天SQL筑基》 文章目录零、前言一、什么是数据库引擎二、MYSQL中有哪些数据库引擎2.1、MyISAM2.2、Memoey2.3、InnoDB三、MyISAM和InnoDB的区别3.1、MYSQL版本支持默认引擎不同MyISAMInnoDB3.2、数据的存储结构不同MyISAMInnoDB3.3、存储空间的消耗不同MyISAMIn…

新闻稿写作指南

当你想要传达一则新闻&#xff0c;写一份新闻稿是非常必要的。新闻稿的目的是让读者了解某个事件或信息&#xff0c;以及提供与之相关的背景信息和重要细节。以下是新闻稿的写作指南&#xff0c;帮助你写出一份清晰、简洁、有价值的新闻稿。1、选择一个有新闻价值的主题你的新闻…

MySQL参数优化之join_buffer_size

1.查看当前值 show variables like %join_buffer_size%mysql默认该设置为128 或 256 或512k&#xff0c;各个版本有所出入 2.作用范围 在mysql中表和表进行join时候&#xff0c;无论是两个表之间还是多个表之间&#xff0c;join的情况大致分为下面几种情况 join key 有索引 …

leaflet 设置一个图层或者多个图层的透明度(075)

第075个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+leaflet中如何设置一个图层或者多个图层的透明度,利用了layer的setOpacity方法。 直接复制下面的 vue+leaflet源代码,操作2分钟即可运行实现效果 文章目录 示例效果配置方式示例源代码(共137行)相关API参考:专…

Windows保护机制GS:原理及SEH异常处理突破

前言 本次文章只用于技术讨论&#xff0c;学习&#xff0c;切勿用于非法用途&#xff0c;用于非法用途与本人无关&#xff01; 所有环境均为本地环境分析&#xff0c;且在本机进行学习。 GS机制并没有对SEH提供保护&#xff0c;换句话说我们可以通过攻击程序的异常处理达到绕…

【java 高并发编程之JUC】2w字带你JUC从入门到精通

点击查看脑图目录地址,实时更新 1 什么是 JUC 1.1 JUC 简介 在 Java 中&#xff0c;线程部分是一个重点&#xff0c;本篇文章说的 JUC 也是关于线程的。JUC 就是 java.util .concurrent 工具包的简称。这是一个处理线程的工具包&#xff0c;JDK 1.5 开始出现的。 1.2 进程与…

Leetcode_part1

Content [1. Two Sum](https://leetcode.com/problems/two-sum/)Solution 1Solution 2[递归: 17. 电话号码的字母组合](https://leetcode.com/problems/letter-combinations-of-a-phone-number/)Solution 1 暴力Soulution 2 回溯Solution 3 队列[18. 四数之和](https://leetcod…

app截图+识别截图中的文字

在自动化测试的过程中&#xff0c;我们会经常遇到需要进行文字识别的场景&#xff0c;比如 识别验证码、识别截图中的文字、读取截图中的数值 等等&#xff0c;遇到这些情况时我们可以如何处理呢&#xff1f; 本机要有PaddleOCR环境&#xff0c;PaddleOCR可参考我另一篇 Padd…

存储类别、链接与内存管理(二)

0、前言概要 本篇来自于我的另外一篇博客存储类别、链接与内存管理&#xff08;一&#xff09;的续篇&#xff0c;主要分析了C语言中的不同存储类别、关键字以及使用的注意事项 1、自动变量 &#xff08;1&#xff09;属性 自动存储期、块作用域、无连接 &#xff08;2&a…

vue项目实现会议预约(包含某天的某个时间段和某月的某几天)

一、一天的时间段预约 会议预约有以下操作&#xff1a; 1.点击预约按钮&#xff0c;弹窗最近一周的预约时间点&#xff08;半小时一个点&#xff09;&#xff0c;预约时间为5:00到24:00; 2.超过当前时间的时间点不允许再预约&#xff0c;已经预约的时间不允许再预约&#xff0c…