lesson-2C++类与对象(中)

个人主页:Lei宝啊 

愿所有美好如期而遇


目录

类的6个默认成员函数

构造函数

概念

特性

析构函数

概念

特性

拷贝构造函数

概念

特性

赋值运算符重载

运算符重载

赋值运算符重载

前置++和后置++重载

日期类的实现


类的6个默认成员函数

如果一个类中什么成员都没有,简称为空类。
class null   //null是类名
{

};
空类中真的什么都没有吗?并不是,任何类在什么都不写时,编译器会自动生成以下6个默认成员
函数。

构造函数

概念

我们可以先通过一个对象的初始化函数引入。

#include <iostream>
using namespace std;

class Date
{

public:
	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}

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

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

int main()
{
	Date a;

	a.Init(2023, 10, 20);
	a.Print();

	return 0;
}

每一次我们创建出一个对象都要手动为其初始化,如果忘了的话,轻点是随机值,重点程序就崩了,所以我们的构造函数就解决了这个问题。

构造函数 是一个 特殊的成员函数,名字与类名相同 , 创建类类型对象时由编译器自动调用 ,以保证
每个数据成员都有 一个合适的初始值,并且 在对象整个生命周期内只调用一次

看代码。 

#include <iostream>
using namespace std;

class Date
{

public:
	
    //构造函数支持重载
	Date()
	{
		_year = 1;
		_month = 1;
		_day = 1;
	}

	Date(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}


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

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

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

 我们可以看到我们a对象里的年月日确实有值了,被我们所写的的默认构造函数所调用,并全部赋值为1.

接下来我们试试有参数的构造函数。

int main()
{

	Date a(2023,10,21);
	a.Print();
	
	return 0;
}

我们发现编译器调用的是我们有参数的构造函数。

特性

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

 在上述代码中,也体现出了构造函数的这四个特性。

但是有几点我们要注意

1:没有参数的构造函数,系统默认的构造函数,全缺省的构造函数,都叫做默认构造函数,而这三个构造函数不可同时写出,任意二者不可同时存在,我们看代码解释。

class Date
{
public:

	Date()
	{
		_year = 1;
		_month = 1;
		_day = 1;
	}

	Date(int year = 10, int month = 10, int day = 10)
	{
		_year = year;
		_month = month;
		_day = day;
	}


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

int main()
{

	Date a;

	return 0;
}

因为编译器无法区分到要调用哪个构造函数,所以就报错了。

2:当我们定义了构造函数后,编译器不会再生成默认构造函数,但这样也会出现一个小问题需要我们去掌控。

class Date
{
public:

	Date(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}

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

int main()
{

	Date a;

	return 0;
}

因为我们自定义了一个构造函数,所以系统不会再生成默认构造函数,而我们实例化的对象要调用无参的构造函数,但是我们又没有无参的构造函数,所以编译器就只能报错,我们后面会讲到有解决方法。

3.如果说我们没有写构造函数,内置类型的成员变量使用系统的默认构造函数,不会做处理,自定义类型的成员变量会去调用他自己的默认构造函数。

解释:内置类型就是系统自带的,比如int,double之类的,像类和结构体等就是自定义类型。

class Stack
{

public:
	Stack(int capacity = 4)
	{
		_capacity = capacity;
		int top = 0;
		int* a = (int*)malloc(sizeof(int) * capacity);
	}

	~Stack()
	{
		free(_a);
		_top = 0;
		_capacity = 0;
	}

private :
	int* _a;
	int _top;
	int _capacity;

};

class Queue
{
	Stack _a;
	Stack _b;
	int size;
};

int main()
{

	Stack a;
	Queue b;

	return 0;
}

细心的朋友们可能会发现size被初始化为0了,你不是说内置类型的变量不初始化吗?是的,但是不同的编译器处理结果不同,我这个是Visual Studio 2022 ,在2013下是不会给初始化的,我们想要我们写出的代码具有跨平台性,就不要寄希望于编译器会给优化,所以我们就当做他不会给优化处理,写出优质代码。

4:C++11新特性,允许声明成员变量时给默认值。

class Date
{

public:
	void Print()
	{
		cout << _year << _month << _day;
	}

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

int main()
{

	Date a;
	a.Print();

	return 0;
}

析构函数

概念

通过前面构造函数的学习,我们知道一个对象是怎么来的,那一个对象又是怎么没呢的?
析构函数:与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作是由
编译器完成的。而 对象在销毁时会自动调用析构函数,完成对象中资源的清理工作
像我们上面有代码~Stack就是析构函数。

特性

析构函数 是特殊的成员函数,其 特征 如下:
1. 析构函数名是在类名前加上字符 ~
2. 无参数无返回值类型。
3. 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。
    注意:析构函数不能重载
4. 对象生命周期结束时, C++ 编译系统系统自动调用析构函数

 我们来测试一下。

class Stack
{

public:
	Stack(int capacity = 4)
	{
		_capacity = capacity;
		int top = 0;
		int* a = (int*)malloc(sizeof(int) * capacity);
	}

	~Stack()
	{
		free(_a);
		_top = 0;
		_capacity = 0;
		cout << "haha" << endl;
	}

private :
	int* _a;
	int _top;
	int _capacity;

};

class Queue
{
	Stack _a;
	Stack _b;
	int size;
};

int main()
{

	Queue b;

	return 0;
}

结果显而易见,我们的确是调用了析构函数。

拷贝构造函数

概念

拷贝构造函数 只有单个形参 ,该形参是对本 类类型对象的引用 ( 一般常用 const 修饰 ) ,在用 已存
在的类类型对象创建新对象时由编译器自动调用

特性

我们先来写一段代码证明拷贝构造函数的必要性

首先是日期类的测试

class Date
{

public:
	Date(int year = 2023, int month = 10, int day = 22)
	{
		_year = year;
		_month = month;
		_day = day;

		cout << "Date的构造" << endl;
	}
	
private:
	int _year;
	int _month;
	int _day;

};

void func1(Date a)
{
	cout << "func1(Date a)" << endl;
}

int main()
{

	Date d1(2023, 10, 22);
	func1(d1);	

	return 0;

}
注意日期类函数调用的析构函数是系统默认的,而且也没什么需要释放的。
所以在我们将d1这个对象传给func1这个函数的时候时值传递,当fun1结束时,a这个对象要销毁,会去调用析构函数。
接下来我们来看栈这个类
class Stack
{

public:
	Stack(int capacity)
	{
		_capacity = capacity;

		int top = 0;
		_a = (int*)malloc(sizeof(int) * _capacity);
		if (_a == nullptr)
		{
			perror("malloc");
		}

		cout << "Stack的构造" << endl;
	}

	~Stack()
	{
		free(_a);
		_a = nullptr;

		_top = 0;
		_capacity = 0;

		cout << "Stack的析构" << endl;
	}
	
private:
	int* _a;
	int _top;
	int _capacity;

};

void func2(Stack st)
{
	//...
}

int main()
{
	
	Stack st1(4);
	func2(st1);

	return 0;

}

这个栈类再这么调用就会出问题,当st销毁时,去调用我们所写的析构函数,在func2函数结束时会释放一次_a,当主函数中的对象st1销毁时,会对已经释放的那块空间再释放一次,这样程序就崩溃了,因为此时的_a就是野指针了,别忘了我们是传值,空间释放后_a就成了野指针,释放野指针指向的空间是不合法的,所以就崩了。

那也许有人会说,我传引用不就好了吗,但是假设我们有一个需求,不改变对象本身,就是要拷贝一份去实现,那么拷贝构造就凸显出作用来了。(如果还有人说栈这个类我用系统默认的析构函数不好吗?那您可真是昏了头了)

拷贝构造函数也是特殊的成员函数,其 特征 如下:
1. 拷贝构造函数 是构造函数的一个重载形式
Stack(int capacity)
{
	_capacity = capacity;

	int top = 0;
	_a = (int*)malloc(sizeof(int) * _capacity);
	if (_a == nullptr)
	{
		perror("malloc");
	}

	cout << "Stack的构造" << endl;
}

//拷贝构造
Stack(const Stack& st)
{
	_top = st._top;
	_capacity = st._capacity;
	_a = (int*)malloc(sizeof(int) * _capacity);
	if (_a == nullptr)
	{
		perror("malloc");
	}
}

2. 拷贝构造函数的 参数只有一个 必须是类类型对象的引用 ,使用 传值方式编译器直接报错
因为会引发无穷递归调用。
拷贝构造参数不引用为什么会引发无穷递归呢?
首先要明白在传值拷贝自定义类型定义出的对象时,编译器会去调用他的拷贝构造,我们传值传参Stack类型的对象,也就是要拷贝一份给参数,所以编译器会去调这个对象的拷贝构造,我们去掉引用后的拷贝构造是这个样子的
Stack(const Stack st)
{
	_top = st._top;
	_capacity = st._capacity;
	_a = (int*)malloc(sizeof(int) * _capacity);
	if (_a == nullptr)
	{
		perror("malloc");
	}
}

接下来我们通过图解来看一看无穷递归的出现原因。

所以我们要加上&。

3. 若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按
字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。
我们的日期类是不用我们再去单独写拷贝构造函数的,因为系统默认的拷贝构造函数就是值拷贝。
拷贝构造函数典型调用场景:
使用已存在对象创建新对象
Stack st2(st1);
函数参数类型为类类型对象
当然,一般来说,没有特别要求,我们还是推荐使用引用的,效率会高些。
void func2(Stack st)
{
	//...
}
函数返回值类型为类类型对象
Date func3(Date d)
{
	//如果出了作用域,传值给d的对象还存在,
	//那么引用返回更好,这里我们只是为了举例子
	//而且我们是推荐传引用的
	return d;
}

返回的时候,d已然销毁,所以我们返回的其实是d的拷贝。

为了提高程序效率,一般对象传参时,尽量使用引用类型,返回时根据实际场景,能用引用
尽量使用引用。

赋值运算符重载

这里我们还是会通过一些例子来引入这个概念。

我们打算写个日期类来解释,在此之前,我们需要先明白,日期和日期的相加减有没有意义,比如

2023-10-23 + 2023-10-24,显然是没有意义的,但是他们之间相减就有了意义;两个日期相差多少天,那么日期间的乘除也是没有意义的;再看2023-10-23 + 50天,这个显然也是有意义的,计算50天日期是多少;这么说的话,其实日期的比较也是有意义的,相等和大小。

那么我们如何去实现日期间的比较和日期加减天数呢?

但是这些成员变量都是私有的,在类外我们不能直接用,当然,我们可以在类里写上GetYear函数等来取得他们的值进行比较,我们这里只是测试,就先将他们公开,当然这样的代码是不健康的,但是我们也说了,只是测试。

class Date
{

public:
	Date(int year = 2023, int month = 10, int day = 22)
	{
		_year = year;
		_month = month;
		_day = day;

		cout << "Date的构造" << endl;
	}

	int _year;
	int _month;
	int _day;

};

bool equal(Date d1, Date d2)
{
	if (d1._year == d2._year && d1._month == d2._month && d1._day == d2._day)
		return true;
	else
		return false;
}

int main()
{

	Date d1;
	Date d2(2023, 2, 13);

	bool ret = equal(d1, d2);
	cout << ret << endl;

	return 0;
}

当然,这样会更好些

bool equal(const Date& d1, const Date& d2)
{
	if (d1._year == d2._year && d1._month == d2._month && d1._day == d2._day)
		return true;
	else
		return false;
}

 接下来进行大小比较函数,起个什么名字好呢?compare?比大还是比小?我怎么知道,compare_large? 当下,我们先随便起名字。

class Date
{

public:
	Date(int year = 2023, int month = 10, int day = 22)
	{
		_year = year;
		_month = month;
		_day = day;

		cout << "Date的构造" << endl;
	}

	int _year;
	int _month;
	int _day;

};

bool equal(const Date& d1, const Date& d2)
{
	if (d1._year == d2._year && d1._month == d2._month && d1._day == d2._day)
		return true;
	else
		return false;
}

bool compare(const Date& d1, const Date& d2)
{

	if (d1._year > d2._year)
	{
		return true;
	}
	else if (d1._year == d2._year && d1._month > d2._month)
	{
		return true;
	}
	else if (d1._year == d2._year && d1._month == d2._month && d1._day > d2._day)
	{
		return true;
	}

	return false;
}

int main()
{

	Date d1;
	Date d2(2023, 2, 13);

	bool ret1 = equal(d1, d2);
	bool ret2 = compare(d1, d2);

	cout << ret1 << endl;
	cout << ret2 << endl;

	return 0;
}

 

我们可以想想内置类型定义出的变量,都是可以直接比较和相加减的,那么我自定义类型定义的对象能不能也直接比较相加减呢?答案是不能,编译器无法理解对象如何比较,比如我们的d1和d2,怎么确定大小呢?年月日都大于才算大于吗?由此,我们引入一个新的概念,运算符重载,不进解决了函数名不便于理解的问题,还可以进行对象的比较。

运算符重载

C++ 为了增强代码的可读性引入了运算符重载 运算符重载是具有特殊函数名的函数 ,也具有其
返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。
函数名字为:关键字 operator 后面接需要重载的运算符符号
函数原型: 返回值类型  operator 操作符 ( 参数列表 )
看代码前别忘了六个成员函数每个函数都有一个隐含的this指针。
class Date
{

public:
	Date(int year = 2023, int month = 10, int day = 22)
	{
		_year = year;
		_month = month;
		_day = day;

		cout << "Date的构造" << endl;
	}
    
    //比较相等
	bool operator==(const Date& d2)
	{
		if (_year == d2._year &&_month == d2._month && _day == d2._day)
			return true;
		else
			return false;
	}

    //比较大于
	bool operator>(const Date& d2)
	{

		if (_year > d2._year)
		{
			return true;
		}
		else if (_year == d2._year && _month > _month)
		{
			return true;
		}
		else if (_year == d2._year && _month == d2._month && _day > d2._day)
		{
			return true;
		}

		return false;
	}

private:
	int _year;
	int _month;
	int _day;

};

int main()
{

	Date d1;
	Date d2(2023, 2, 13);

	//bool ret1 = equal(d1, d2);
	//bool ret2 = compare(d1, d2);

	bool ret1 = d1 == d2; //d1.operator==(d2);
	bool ret2 = d1 > d2;  //d1.operator>(d2);

	cout << ret1 << endl;
	cout << ret2 << endl;

	bool ret3 = d1.operator==(d2);
	bool ret4 = d1.operator>(d2);

	cout << ret1 << endl;
	cout << ret2 << endl;

	return 0;
}
注意:
  1. 不能通过连接其他符号来创建新的操作符:比如operator@
  2. 重载操作符必须有一个类类型参数
  3. 用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不 能改变其含义
  4. 作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this
  5. .* :: sizeof ?: . 注意以上5个运算符不能重载。这个经常在笔试选择题中出现。

写在类外面,只写一个参数就是如下图结果; 

 

因为大于的比较有两个操作数。

接下来是日期加上一个数。

·

class Date
{

public:
	Date(int year = 2023, int month = 10, int day = 22)
	{
		_year = year;
		_month = month;
		_day = day;

		cout << "Date的构造" << endl;
	}

	int GetMonthday(int year, int month)
	{
		int month_day[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };

		if (month == 2 && (year % 4 == 0 && year % 100 == 0 || year % 400 == 0))
		{
			return 29;
		}

		return month_day[month];
	}

	Date& operator+=(int day)
	{
		_day += day;

		while (_day > GetMonthday(_year,_month))
		{
			_day -= GetMonthday(_year, _month);
			_month++;

			if (_month == 13)
			{
				_year++;
				_month = 1;
			}
		}

		return *this;
	}

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

private:
	int _year;
	int _month;
	int _day;

};

int main()
{

	Date d1;
	d1 += 50;

	d1.Print();

	return 0;
}

但是这样我们把对象d1就做了修改,我们不想修改,只想+然后返回来一个值怎么办?

将下面这个代码加入类中

	Date operator+(int day)
	{
        //实例化一个对象tmp拷贝*this
		Date tmp(*this);

        //复用operator+=
		tmp += 50;
	
		return tmp;
	}

int main()
{

	Date d1;

	Date d2 = d1 + 50;
	d2.Print();

	return 0;
}

 

接下来就是我们的赋值运算符重载了。

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

	return *this;
}

前置++和后置++重载

前置和后置++,最难以区分的其实是他们的名字,尽管返回值不同,但参数相同,不构成重载,于是就有了一个特殊规定,看代码

C++规定:后置++重载时多增加一个int类型的参数,但调用函数时该参数不用传递,编译器
自动传递
//前置++复用operator+=
Date& Date::operator++()
{
	*this += 1;
	return *this;
}

//后置++复用operator+=
Date Date::operator++(int)
{
	Date tmp(*this);
	*this += 1;

	return tmp;
}

于是我们用参数类型来区分,一个不传,一个传int类型,编译器就可以区分了。

一般情况下我们最好还是用前置++,是引用返回,而且没有拷贝,后置++就有一次拷贝,也许一次调用差距不大,但是如果调用10万次就有差别了。

日期类的实现

接下来我们将使用各种运算符重载实现各种有意义的日期比较和加减,

头文件 

#pragma once
#include <iostream>
using namespace std;

class Date
{

public:

	Date(int year = 2023, int month = 10, int day = 24);
	
	int GetMonthday(int year, int month);
	
	//operator+复用opreator+=,优于operator+=复用operator+
	Date operator+(int day);
	Date operator-(int day);        //计算日期减天数
	int operator-(const Date& d);   //计算日期和日期间差几天
	Date& operator+=(int day);
	Date& operator-=(int day);
	Date& operator=(const Date& d);
	
	bool operator==(const Date& d);
	bool operator!=(const Date& d);
	bool operator>(const Date& d);
	bool operator<(const Date& d);
	bool operator>=(const Date& d);
	bool operator<=(const Date& d);
	
	//前置++复用operator+=
	Date& operator++();
	//后置++复用operator+=
	Date operator++(int);
	
	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}

private:
	int _year;
	int _month;
	int _day;

};
 

日期类的实现 

#include "Date.h"

Date::Date(int year, int month, int day)
{
	_year = year;
	_month = month;
	_day = day;
}

int Date::GetMonthday(int year, int month)
{
	int month_day[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };

	if (month == 2 && (year % 4 == 0 && year % 100 == 0 || year % 400 == 0))
	{
		return 29;
	}

	return month_day[month];
}

Date& Date::operator+=(int day)
{
	_day += day;

	while (_day > GetMonthday(_year, _month))
	{
		_day -= GetMonthday(_year, _month);
		_month++;

		if (_month == 13)
		{
			_year++;
			_month = 1;
		}
	}

	return *this;
}

Date Date::operator+(int day)
{
	Date tmp(*this);
	tmp += 50;

	return tmp;
}

Date  Date::operator-(int day)
{
	Date tmp(*this);
	tmp -= day;

	return tmp;
}

Date& Date::operator-=(int day)
{
	if (day < 0)
	{
		return *this += -day;
	}

	_day -= day;
	while (_day <= 0)
	{
		--_month;
		if (_month == 0)
		{
			--_year;
			_month = 12;
		}

		_day += GetMonthday(_year, _month);

	}
}


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

	return *this;
}

//前置++复用operator+=
Date& Date::operator++()
{
	*this += 1;
	return *this;
}

//后置++复用operator+=
Date Date::operator++(int)
{
	Date tmp(*this);
	*this += 1;

	return tmp;
}

bool Date::operator>(const Date& d)
{

	if (_year > d._year)
	{
		return true;
	}
	else if (_year == d._year && _month > _month)
	{
		return true;
	}
	else if (_year == d._year && _month == d._month && _day > d._day)
	{
		return true;
	}

	return false;
}

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

bool Date::operator!=(const Date& d)
{
	return !(*this == d);
}

bool Date::operator<(const Date& d)
{
	return !(*this >= d);
}

bool Date::operator>=(const Date& d)
{
	return *this > d || *this == d;
}

bool Date::operator<=(const Date& d)
{
	return !(*this <= d);
}


int Date::operator-(const Date& d)
{
	int flag = 1;
	Date max = *this;
	Date min = d;

	if (max < min)
	{
		max = d;
		min = *this;
		flag = -1;
	}

	int n = 0;
	while (min != max)
	{
		++min;
		++n;
	}

	return n * flag;
}

测试 

#include "Date.h"

int main()
{
	
	Date d1;

	//测试赋值运算符重载
	Date d2 = d1;
	cout << "测试d2赋值运算符重载" << endl;
	d2.Print();

	//测试+运算符重载
	Date d3(2023, 10, 25);
	d3 = d3 + 50;
	cout << "测试d3+运算符重载" << endl;
	d3.Print();

	//测试-运算符重载
	Date d4(2023, 10, 25);
	d4 = d4 - 50;
	cout << "测试d4-运算符重载" << endl;
	d4.Print();

	//测试==运算符重载
	Date d5(2023, 10, 25);
	d5 = d5 - 50;
	cout << "测试d5==运算符重载" << endl;
	cout << (d4 == d5) << endl;

	//测试!=运算符重载
	Date d6(2023, 10, 25);
	cout << "测试d6!=运算符重载" << endl;
	cout << (d4 == d6) << endl;

	//测试++运算符重载
	Date d7(2023, 10, 25);
	cout << "测试d7++运算符重载" << endl;
	++d7;
	d7.Print();

	//测试>=运算符重载
	Date d8(2023, 10, 25);
	cout << "测试d8>=运算符重载" << endl;
	cout << (d7 >= d8) << endl;
	
	cout << endl << "全部通过" << endl;
	return 0;
}

测试结果 

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

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

相关文章

掌握CSS动画技巧:打造引人注目的页面过渡效果!

&#x1f3ac; 江城开朗的豌豆&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 &#x1f4dd; 个人网站 :《 江城开朗的豌豆&#x1fadb; 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! ​ 目录 ⭐ 专栏简介 &#x1f4d8; 文章引言 一…

jquery-picture-cut 任意文件上传 (CVE-2018-9208)

jquery-picture-cut 任意文件上传 &#xff08;CVE-2018-9208&#xff09; 漏洞描述 picture cut是一个jquery插件&#xff0c;以非常友好和简单的方式处理图像&#xff0c;具有基于bootstrap或jquery ui的漂亮界面&#xff0c;具有ajax上传&#xff0c;从资源管理器拖动图像…

MySQL 连接出现 Authentication plugin ‘caching_sha2_password的处理方法(使用第二种)

出现这个原因是mysql8 之前的版本中加密规则是mysql_native_password,而在mysql8之后,加密规则是caching_sha2_password, 解决问题方法有两种,一种是升级navicat驱动,一种是把mysql用户登录密码加密规则还原成mysql_native_password. 1. 升级MySQL版本 较早的MySQL版本可能不…

冒泡排序:了解原理与实现

目录 原理 实现 性能分析 结论 冒泡排序&#xff08;Bubble Sort&#xff09;是一种简单但效率较低的排序算法。它重复地比较相邻的元素并交换位置&#xff0c;直到整个序列有序为止。虽然冒泡排序的时间复杂度较高&#xff0c;但在小规模数据集上仍然具有一定的实际应用价…

Java开发者必备:支付宝沙箱环境支付远程调试指南

&#x1f525;博客主页&#xff1a; 小羊失眠啦. &#x1f516;系列专栏&#xff1a; C语言、Linux、Cpolar ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 文章目录 前言1. 下载当面付demo2. 修改配置文件3. 打包成web服务4. 局域网测试5. 内网穿透6. 测试公网访问7. 配置二级…

集卡实习总结

规则控制面板 &#xff08;1&#xff09;什么是低代码&#xff1f; 低代码 是借助低代码工具的情况下&#xff0c;开发人员编写少量代码快速开发出企业级应用系统&#xff0c;并帮助企业团队进行数字化转型。低码开发平台借助一整套功能组件&#xff0c;功能分类包括&#xff…

文心一言简单体验

百度正式发布文心一言&#xff0c;文心一言 这里的插件模式挺有意思&#xff1a; 测试了一下图解说明&#xff0c;随意上传了一张图片&#xff1a; 提供图解让反过来画&#xff0c;抓住了部分重点&#xff0c;但是还是和原图有比较大的差异&#xff01; 百宝箱 暂未逐个体验&am…

RPA除了和OCR、NLP技术结合,还能和什么技术结合?

鉴于业内现在也经常把RPA称为数字员工&#xff0c;就虚拟一个人的形象来解答吧。 首先是头部&#xff0c;实现人的“听看说想”能力&#xff1a; 听&#xff1a;ASR&#xff08;语音识别技术&#xff09;&#xff0c;主要用于听取和理解语音输入&#xff0c;让RPA能处理语音数…

人性与理性共赢,真心罐头跃过增长的山海关

在北方不少地方&#xff0c;黄桃罐头是一种抚慰人心的力量。从大连起家&#xff0c;用真材实料打动人心的真心罐头&#xff0c;在朝着国民品牌前进的路上&#xff0c;需要更透彻地洞悉“人性”。 ”人的因素影响太大。我们希望可以告别个人英雄主义&#xff0c;用流程来保证可…

学会Docker之——界面化操作(Docker Desktop)

Docker Desktop 是一款用于在桌面环境下开发、构建和容器化应用程序的工具。它适用于 Windows 和 Mac 操作系统&#xff0c;让开发人员可以轻松地在本地环境中创建和运行容器&#xff0c;并与 Docker Hub 和其他容器注册表进行交互。Docker Desktop集成了Docker Engine&#xf…

【蓝桥杯】蓝桥杯双周赛第二场ABCD题

A题&#xff1a;新生 知识点&#xff1a;下一届是第几届蓝桥杯…… 新一届蓝桥杯大赛即将在2024年拉开序! 作为大一新生的小蓝&#xff0c;在听说了这场盛大的比赛后&#xff0c;对其充满了期待与热情。但作为初次参赛的新手&#xff0c;他对蓝桥杯的相关赛制和历史并…

SpringMVC探秘: 实现MVC模式的Web应用

文章目录 1. SpringMVC概述1.1. 什么是SpringMVC&#xff1f;1.1.1. MVC与SpringMVC 1.2. SpringMVC项目的优势 2. SpringMVC项目的创建与使用2.1. 创建SpringMVC项目2.2. 设置路由2.3. 获取参数2.3.1. 获取一个参数2.3.2. 获取多个参数2.3.3. 获取日期参数2.3.4. 参数重命名Re…

MS COCO数据集的评价标准以及不同指标的选择推荐(AP、mAP、MS COCO、AR、@、0.5、0.75、1、目标检测、评价指标)

目标检测模型性能衡量指标、MS COCO 数据集的评价标准以及不同指标的选择推荐 0. 引言 0.1 COCO 数据集评价指标 目标检测模型通过 pycocotools 在验证集上会得到 COCO 的评价列表&#xff0c;具体参数的含义是什么呢&#xff1f; 0.2 目标检测领域常用的公开数据集 PASCAL …

vmware17.0|ubuntu22.04.0 解决灰色Vmware Tool 无法重新安装和 无法和win11相互拖拽文件问题

文章目录 版本&#xff1a;问题&#xff1a;解决方法 版本&#xff1a; vmware 17.0 ubuntu 22.04.0 win11 问题&#xff1a; 无法和windows互相复制粘贴文件 解决方法 1.关闭虚拟机 2.开启虚拟机&#xff0c;在开启虚拟机的过程中再次查看发现灰色图标可点击&#xff0c…

iOS iGameGuardian修改器检测方案

一直以来&#xff0c;iOS 系统的安全性、稳定性都是其与安卓竞争的主力卖点。这要归功于 iOS 系统独特的闭源生态&#xff0c;应用软件上架会经过严格审核与测试。所以&#xff0c;iOS端的作弊手段&#xff0c;总是在尝试绕过 App Store 的审查。 常见的 iOS 游戏作弊&#xf…

Java 基础面试题,JVM 内存模型?

我们在 Java 岗位的面试题中&#xff0c;大概率会碰到这样一个面试题&#xff1a;请你解释你对 JVM 内存模型的理解。 今天我们就来回答一下这个问题&#xff1a; JDK 11 中的 JVM 内存模型可以分为以下几个部分&#xff1a; 程序计数器&#xff08;Program Counter&#xff…

随笔:使用Python爬取知乎上相关问题的所有回答

项目中数据分析的需要自己从知乎某个专门的问题上爬数据&#xff0c;但众所周知&#xff0c;知乎的问题的显示方式有点胃疼&#xff08;指滑动后下翻加载更多回答&#xff0c;还经常卡住&#xff09;&#xff0c;翻了翻网上的教程发现有的要么就是很老了要么就是付费的&#xf…

支付宝证书到期更新完整过程

如果用户收到 支付宝公钥证书 到期通知后&#xff0c;可以根据如下指引更新证书 确认上传成功后就会生成新的证书&#xff0c;把新的证书替换到生产环境就可以了

uniapp:谷歌地图,实现地图展示,搜索功能,H5导航

页面展示 APP H5 谷歌地图功能记录,谷歌key申请相对复杂一些,主要需要一些国外的身份信息。 1、申请谷歌key 以下是申请谷歌地图 API 密钥的流程教程: 登录谷歌开发者控制台:打开浏览器,访问 Google Cloud Platform Console。 1、创建或选择项目:如果你还没有创建项目…

搭建docker本地仓库

1.拉取私有仓库镜像 [rootmaster1 ~]# docker pull registry [rootmaster1 ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE nginx v1 546db553f62a About an hour ago …