初识C++ · 类和对象(中)(2)

news2025/3/10 11:17:01

前言:上篇文章已经介绍了6个默认成员函数中的3个函数,分别是构造函数,析构函数,拷贝构造函数,本文介绍的是后三个,赋值运算符重载const成员函数取地址操纵符重载


目录​​​​​​​

1 赋值运算符重载

1.1运算符重载

1.2 赋值重载

2 实现日期类


1 赋值运算符重载

1.1运算符重载

在学习赋值运算符重载之前,我们先来介绍一下运算符重载:
C++为了增加代码的可读性,引用了运算符重载的概念,运算符重载其实就是一个特殊一点点的函数,返回值,参数,返回类型都是有的,那么运算符重载后的函数名是什么呢?

运算符重载的关键字是operator,函数名就是operator加后面的运算符,比如:

bool operator==(Date d1,Date d2);

operator==就是函数名,参数是两个日期类,返回值是true false,返回类型是bool。

其中,返回值,返回类型等都是根据实际情况操作的,比如日期减日期,返回类型是int,因为返回值是相差的天数,比如日期减天数,返回值就是日期类,因为返回值就是日期,所以实际的返回值返回类型参数等都是看实际情况的,没有固定的说法。

当我们比较一个数是否相等时候,我们直接:

int a = 0;
int b = 1;
bool ret = a == b;

直接利用运算符比较就行,但是对于日期类的我们不能这样干,因为直接比较的都是内置类型,在C++中可以直接进行比较的就是内置类型,但是自定义类型不可以直接比较,这个时候就需要用到运算符重载了,用法如:

bool operator==(Date d1, Date d2)
{
	return d1._year == d2._year && d1._month == d2._month && d1._day == d2._day;
}

这是函数的定法方法,那么定义的时候我们需要注意operator的使用:
1 不能通过连接其他符号来创建新的操作符:比如operator@

2 重载操作符必须有一个类类型参数

3 用于内置类型的运算符,其含义不能改变

4 作为类成员函数重载时,其形参看起来比操作数数目少1

5  .* :: sizeof ?: . 注意以上5个运算符不能重载。这个经常在笔试选择题中出现

我们不能使用C++里面没有的符号来创建新的符号,因为没有实际意义,编译器也走不过去。

内置类型的比较我们可以直接调用运算符,编译器调用指令来执行代码,重载的操作符是用于自定义类型的,参数没有类是不行的,比如int operator-(int a,int b),两个内置类型重载完全没有意义,所以重载的操作符的参数一定要有个类。

其实严格意义上来说,重载操作符可以改变原来的含义,比如重载一个+,实现的时候实现的是减法,有问题吗?没有多大问题,可能是用来整蛊代码呢?但是实际写代码的时候还是不要改变的好,不然要挨打咯。

当重载函数作为成员函数的时候,因为成员函数都有个默认的成员函数指针,所以形参看起来比操作数少一个。

sizeof ?: . ::这几个操作符好说,不能重载,不常见的是.*,这个是成员函数指针,我们简单看一下函数指针的用法:

void Func()
{
	cout << "Func" << endl;
}
int main()
{
	void(*pf)() = Func;
	(*pf)();
	return 0;
}

其中函数指针类型是void()(),这里简单复习一下即可,因为函数名就是地址,所以函数指针取地址的时候是没有加&的,那么成员函数指针:

class Ob
{
public:
	void Func()
	{
		cout << "hahaha" << endl;
	}
};
int main()
{
	Ob o1;
	void(Ob:: *pf)() = &Ob::Func;
	(o1.*pf)();
	return 0;
}

成员函数指针和普通函数指针的差别就在于规定了成员函数指针取地址的时候必须加&,调用的方法如上,这个运算符也是不能被重载的。

operator介绍完了后,调用运算符重载函数分为显式调用和转换调用

int main()
{
	Date d1(2020, 1, 17);
	Date d2(2024, 2, 24);
	operator==(d1,d2);
	d1 == d2;
	return 0;
}

显式调用也就是把函数名全部写出来,当然比较麻烦,一般比较喜欢的就是转化调用了,直接d1==d2就可以了,称为转换调用的原因是因为编译器在汇编层面执行代码的时候也是调用的那个函数,即最后都是转换为了operator==(d1,d2)。

最后都是call重载函数。

那么是否现在意味着我们可以随意调用重载函数呢?

答案是不行的,因为全局重载函数要访问的话,类的成员变量一定要是公有的,不然就会报错:
C++提供了三个解决方法:

1 提供这些成员的get和set

2 使用友元

3 重载成成员函数

这里着重介绍的是重载成成员函数,友元后面介绍,get set其实java特别喜欢,大概使用如下:

int Getyear()
{
	return _year;
}
bool operator==(Date d1, Date d2)
{
	return d1.Getyear() == d2.Getyear();
}

了解一下,主要还是重载成成员函数。

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

重载之后,注意参数数目的改变。这里的显式调用就是d1.operator(d2)了。


1.2 赋值重载

Date operator=(const Date& d)
{
	_year = d._year;
	_month = d._month;
	_day = d._day;
	return *this;
}
int main()
{
	Date d1(2020, 1, 17);
	Date d2(2024, 2, 24);
	Date d3 = d1;
	Date d4(1,1,1);
	d4 = d1;
	return 0;
}

我们先来看这样一段代码,d3 = d1,是拷贝还是赋值?d4 = d1是拷贝还是赋值?

答案比较明确,d3 = d1是拷贝构造,d4 = d1是赋值,那么为什么d4 = d1不是拷贝呢?拷贝是拷贝构造,也就是在初始化的时候完成的,d4已经初始化完成了,再调用就是赋值了。

那么再来一个问题:

int main()
{
	int i = 1, j = 2, m = 3;
	i = j = m;
	cout << i << endl;
	return 0;
}

请问赋值的顺序是什么样的?
这里的规定是先执行j =m,返回的是j,再执行i = j,最后赋值完成,也就是说连续赋值需要表达式有一个返回值,比如j = m的返回值就是j,那么执行重载后的连续赋值,就需要函数要有返回值:

那么j = m返回的是j,所以d2 = d3返回的应该是d2,函数的this指针指向的就是d2,也就是说我们要返回d2,但是d2在函数里面不是显式的,是隐式的,所以这个时候this指针就起作用了:
return *this就行。

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

连续赋值的问题就结束了,那么引入一个新代码:

Date Func()
{
	Date d;
	return d;
}
int main()
{
	Func();
	return 0;
}

对构造函数和析构函数加一点打印,方便观察。

	Date(const Date& d)//拷贝构造函数
	{
		cout << "const Date& d" << endl;
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
	~Date()//析构函数
	{
		cout << "~Date" << endl;
		_year = _month = _day = 0;
	}

首先第一个问题,Func函数会调用几次拷贝构造函数和几次析构函数?

调用了一次拷贝构造函数和两次析构函数,可能会问了,明明没有拷贝拷贝复制的代码,怎么会有拷贝函数的调用呢?
这是因为临时变量的存在,创建好Date d之后,因为返回值是日期类,但是d在Func函数调用了之后会析构,因为生命周期已经结束了,那么返回的就是d拷贝给了一个临时变量,调用了拷贝构造函数,注意,这里是先调用的拷贝构造,再是发生了析构,最后就是主函数里面的d发生了析构。

那么,为了效率,可不可以减少拷贝构造函数的调用呢?析构函数是没有办法的,创建了生命周期一到就会销毁,但是我们可以想办法控制拷贝构造的调用。

Date& Func()
{
	Date d(2020,4,17);
	return d;
}
int main()
{
	const Date& d = Func();
	return 0;
}

如果返回值是日期类,并且用引用来接收的话,那就是一定要用const接收的,因为返回的日期类实际上是临时变量,临时变量具有常性,如果不用const接收就会导致权限的放大,编译器会报错的,使用引用是可以减少拷贝构造函数的调用的

这里观察的话Vs2022是看不出来的,2019可以看出来,因为2022的优化有点严重了,所以这里推荐用Vs2019学习。

使用引用返回就没有调用拷贝构造了,只有一次析构的原因是因为引用就是多个名指向一个空间,这里只创建了一个日期类,所以只用析构一次。

但是啊,这里引用返回又是一个很恐怖的事情,为什么呢?

这段代码的本意是:创建一个日期类d,再用一个日期类的引用来接受这个日期类的值。

但是经过了析构函数了之后,原本想的是值应该是2020.4.17,但是因为d析构了,所以主函数的d的值也会变成析构之后的值,但是这还不是最恐怖的,最恐怖的是野引用

Date& Func()
{
	Date d(2020,4,17);
	cout << &d << endl;
	return d;
}
int main()
{
	const Date& d = Func();
	cout << &d << endl;
	return 0;
}

首先两个d指向的空间确实是一样的,我们可以用这段代码观察。

但是随着Func函数的调用完成,也就是说Func函数创建的函数栈帧会被操作系统回收了,但是主函数的d仍然指向的是Func函数中d的那块空间,这就是一个野引用,因为栈帧是从上往下开辟的,如果我们再创建一个函数用来覆盖原来的函数:

Date& Func()
{
	Date d(2020,4,17);
	return d;
}

int F()
{
	int a = 1;
	int b = 2;
	int c = 3;
	return a + b + c;
}

int main()
{
	const Date& d = Func();
	F();
	return 0;
}

那么在Func函数调用完成了之后,Func的函数栈帧被回收,然后就是给F函数创建函数栈帧,因为栈帧是从上往下创建的,F函数的函数栈帧就会覆盖原来Func函数的栈帧,别忘记了此时主函数的d还是指向的那块空间,伴随着函数栈帧的创建,指向的那块空间会给上随机值,那么d就会变成:

d就会变成随机值,d的值可谓是大起大落,从期待的2020.4.17变成了1.1.1再变成了随机值,所以引用的使用也是有风险的,这里总结一下:

如果返回的是临时变量或者是局部变量,会被析构,那么就用传值返回,如果不会被析构函数析构的,那么就用传引用返回,可以减少拷贝构造函数使用次数,主要看的就是生命周期。

如下这种情况:

Date& Func()
{
	static Date d(2020,4,17);
	return d;
}
int main()
{
	const Date& d = Func();
	d.Print();
	return 0;
}
	void Print() const

如果创建的成员是静态的,出了函数不会被析构函数销毁,就用了传引用,这个打印的时候注意一下,后面介绍。

传值传引用大概就结束了,下面来看这段综合的代码:

class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	Date(const Date& d)
	{
		cout << "Date(const Date& d)" << endl;

		_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;
	}
	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
	~Date()
	{
		cout << "~Date()" << endl;
		_year = -1;
		_month = -1;
		_day = -1;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1(2024, 4, 14);
	Date d2(d1);
    Date d3 = d1;
	Date d4(2024, 5, 1);
	d1 = d4;
	d1 = d2 = d4;
	d1 = d1;
	return 0;
}

首先我们先采用传值调用看一遍,引入了一个自己传自己的例子,d1 = d1,严谨一点在重载=这里修改了一下,因为自己等于自己的话赋值没有必要,所以加个判断,直接返回就好了。

这里还有个小细节,前面说生命周期的问题,不免会有人谈论栈的问题,会说只要不在栈上就可以使用引用返回,但是这种想法是错误的,因为这种的默认思维是开辟的元素的栈就是函数的栈帧,但当我们看operator=函数的时候,返回是*this,请问*this在哪个的函数栈帧上?在主函数的函数栈帧上,这里也是栈,但是栈不同,我们可以返回值也可以返回引用,因为这个栈帧是主函数的,随程序的结束才会销毁,所以传值传引用看的是什么?是生命周期

传值调用:
Date d2(d1)一次拷贝构造,Date d3 = d1一次拷贝构造,d1 = d4一次拷贝构造,d2 = d4一次拷贝构造返回d1,d1 = d2一次拷贝构造返回d1,d1 = d1一次拷贝构造返回d1,共6次拷贝构造:

传引用调用:
Date d2(d1)一次拷贝构造,Date d3 = d1一次拷贝构造,后面调用重载函数的返回的都是引用,所以不会调用拷贝构造函数,共两次拷贝构造函数。

最后,赋值运算符重载是默认成员函数,即便用户自己不写,系统也会默认生成,默认生成的赋值运算符重载和拷贝构造函数的行为是一致的,以值的形式进行拷贝,对于日期类,MyQueue类来说默认生成的赋值重载就够用了,但是对于Stack类来说,需要进行深拷贝的类来说就需要用户自己显式定义赋值运算符重载:
读者可以自行注释掉operator=函数,系统也不会报错,因为调用了默认生成的赋值重载,行为就是拷贝构造函数,但是不是拷贝构造函数和赋值重载存在一个就行,存在即合理。

还有就是,赋值重载不能重载成全员函数,因为参数有个一定要是this指针,所以,只能重载成成员函数,这是赋值重载,结束!


2 实现日期类

了解完赋值重载后,我们现在就实现一个真正的日期类:

#pragma once
#include <iostream>
using namespace std;
class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1);
	void Print();
	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);
	~Date();
private:
	int _year;
	int _month;
	int _day;
};

暂时先实现这几个简单的,因为是日期类的,所以拷贝构造函数和赋值重载不用显式定义,编译器生成的默认的就够用了,当然析构函数也是,这里看自己习惯咯,实现这些,其实实现一个就行了:

Date::Date(int year, int month, int day)
{
	_year = year;
	_month = month;
	_day = day;
}
void Date::Print()
{
	cout << _year << '-' << _month << '-' << _day << endl;
}
Date::~Date()
{
	_year = _month = _day = -1;
}

构造 打印 析构这三个函数就是信手拈来,都快写烂了的,这里有个需要注意的,缺省值是在声明的时候给的,在定义的时候又给缺省值就会重定义,编译器报错,在定义和声明的时候分离要注意这个点。

接着就是比较大小的函数:


bool Date::operator>(const Date& d)
{
	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)
{
	return  _year == d._year 
			&& _month == d._month 
			&& _day == d._day;
}
bool Date::operator<(const Date& d)
{
	return !(Date::operator>=(d));
}
bool Date::operator>=(const Date& d)
{
	return Date::operator>(d)
		|| Date::operator==(d);
}
bool Date::operator<=(const Date& d)
{
	return !(Date::operator>(d));
}
bool Date::operator!=(const Date& d)
{
	return !(Date::operator==(d));
}

写了一个函数,其他函数可以说是迎刃而解,比如我写了大于函数,大于等于函数就是大于的同时还满足等于就行,就很简单,无非就是反面正面,当然这段代码并不简洁,简洁一点就使用this指针:

bool Date::operator==(const Date& d)
{
	return  _year == d._year
		&& _month == d._month
		&& _day == d._day;
}
bool Date::operator>=(const Date& d)
{
	return *this > d
		|| *this==d;
}
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);
}
Date::~Date()
{
	_year = _month = _day = -1;
}

用this指针代替之后就会整洁很多了。

然后再来其他函数:

//+ -函数实现
Date& operator+=(int day);
Date& operator-=(int day);

	int GetMonthDay(int year,int month)
	{
		assert(month > 0 && month < 13);
		int yearArr[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 yearArr[2] + 1;
		}
		return yearArr[year];
	}

这里的话在头文件里面定义的日期类里面插入一个函数,它在+ -函数一定是会经常调用的,所以直接定义在类里面使它称为内联函数,直接定义在类里面的就是内联函数,声明和定义不分离,因为链接的时候符号表里面是没有这个函数的名字的。

日期加天数实现的逻辑也很简单,就是天数满了加月,月满了加年而已:

Date& Date::operator+=(int day)
{
	_day += day;
	while (_day < GetMonthDay(_year,_month))
	{
		_day -= GetMonthDay(_year, _month);
		_month++;
		if (13 == _month)
		{
			_year++;
			_month = 1;
		}
	}
	return *this;
}

逻辑很简单,-=同理。

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);
	}
	return *this;
}

这里-=要注意几个点,+=加的是本月的天数,-=加的是上月的天数,所以_day += GetMonthDay(_year,_month)的位置就应该放在判断完之后的位置,当然,有的时候整蛊一下别人,传个负数什么的,那就是反过来相加的事而已,返回去调用一下就可以了。

//+ -实现	
Date operator+(int day);
Date operator-(int day);

这里可以注意到的是这两个函数返回值是值,而不是引用,上面的函数就是引用,因为生命周期。

我们写代码的时候要灵活应用我们已经写过的函数,我们已经写了+=,复用一下就行了,它们唯一的区别就是改不改变已经创建好的日期类的变量。

Date Date::operator+(int day)
{
	Date tem = *this;
	tem += day;
	return tem;
}
Date Date::operator-(int day)
{
	Date tem = *this;
	tem -= day;
	return tem;
}

现在问题来了,是先实现+=,实现+的时候复用+=好呢还是反过来呢?

Date Date::operator+(int day)
{
	Date tmp = *this;
	tmp._day += day;
	while (tmp._day > GetMonthDay(tmp._year, tmp._month))
	{
		tmp._day -= GetMonthDay(tmp._year, tmp._month);
		tmp._month++;
		if (13 == tmp._month)
		{
			tmp._year++;
			tmp._month = 1;
		}
	}
	return tmp;
}
Date& Date::operator+=(int day)
{
	*this = *this + day;
	return *this;
}

对比+=的代码,可以发现上面的代码的简洁度不是很高,而且开始和返回的时候都多了两个拷贝构造,效率降了一点,所以建议+复用+=的代码这种写法。

    //前置++ 后置++
	Date& operator++();//前置++
	Date operator++(int);//后置++
	//前置-- 后置--
	Date& operator++();//前置--
	Date operator++(int);//后置--

前置和后置的区别不用多说了,问题出在我们如何区分前置和后置,本贾尼博士在这里做出的改动是加了一个无用的int参数,有int参数的就是后置操作符,因为没有用,所以我们直接给一个int就行了,实现的话因为前置使用的是操作之前的,所以返回this指针,那么返回引用就会减少拷贝:

//前置++ 后置++
Date Date::operator++(int)//后置++
{
	Date tem = *this;
	*this += 1;
	return tem;
}
Date& Date::operator++()//前置++
{
	*this += 1;
	return *this;
}
//前置-- 后置--
Date& Date::operator--()//前置--
{
	*this -= 1;
	return *this;
}
Date Date::operator--(int)//后置--
{
	Date tem = *this;
	*this -= 1;
	return tem;
}

最后实现一个日期-日期,就得到了一个基本的日期类,但是怎么实现日期-日期呢?因为每个月的天数都不同,所以相对来说有点麻烦,这里用一个比较巧妙的思路:
刚才写了后置前置++,复用呗,比如一个数加到一个数,只要不等于,一直++就可以了,谁大谁小就交给假设法:

	int operator-(const Date& d);//日期相减
int Date::operator-(const Date& d)//日期相减 
{
	Date max = *this;
	Date min = d;
	int flag = 1, num = 0;
	if (*this < d)
	{
		max = d;
		min = *this;
		flag = -1;
	}
	while (max != min)
	{
		min++;
		num++;
	}
	return num * flag;
}

一个完整的日期类就写好了。


感谢阅读!

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

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

相关文章

【Mysql】用frm和ibd文件恢复mysql表数据

问题 总是遇到mysql服务意外断开之后导致mysql服务无法正常运行的情况&#xff0c;使用Navicat工具查看能够看到里面的库和表&#xff0c;但是无法获取数据记录&#xff0c;提示数据表不存在。 这里记录一下用frm文件和ibd文件手动恢复数据表的过程。 思路 1、frm文件&…

371D - Vessels

思路&#xff1a;用并查集维护&#xff0c;如果当前容器没有满&#xff0c;就指向自己&#xff0c;否则指向下一个容器。 这样就可以快速 find 到下一个没有满的容器&#xff0c;从而模拟询问 1。 代码&#xff1a; void solve(){int n;cin >> n;vector<int>p(n …

刷题之Leetcode242题(超级详细)

242.有效的字母异位词 力扣题目链接(opens new window)https://leetcode.cn/problems/valid-anagram/ 给定两个字符串 s 和 t &#xff0c;编写一个函数来判断 t 是否是 s 的字母异位词。 示例 1: 输入: s "anagram", t "nagaram" 输出: true 示例 2…

运维想要不背锅,职责与注意事项,你得仔细看看!

在IT领域&#xff0c;运维人员常常面临着“背锅”的情况。当系统出现故障、服务中断或性能下降时&#xff0c;运维人员往往成为首要责任人。然而&#xff0c;真正的问题并不仅仅是“背锅”&#xff0c;而是在问题发生后如何合理应对和解决。在进行IT运维管理时&#xff0c;我们…

(七)小案例银行家应用程序-申请贷款-some方法和every方法

some方法 ● 我们先回顾一下includes方法 console.log(movements.includes(-130));只要数组中存在-130这个值&#xff0c;就会返回true&#xff0c;否则就会返回flase ● 而some方法只要达成某一个条件就会返回true&#xff0c;否则就返回flase const someMethod movement…

4.23学习总结

一.NIO(一) (一).简介: NIO 是 Java SE 1.4 引入的一组新的 I/O 相关的 API&#xff0c;它提供了非阻塞式 I/O、选择器、通道、缓冲区等新的概念和机制。相比与传统的 I/O 多出的 N 不是单纯的 New&#xff0c;更多的是代表了 Non-blocking 非阻塞&#xff0c;NIO具有更高的并…

ABeam×StartUp丨蓝因机器人访问ABeam旗下德硕管理咨询(深圳)新创部门,展开合作交流

近日&#xff0c;深圳蓝因机器人科技有限公司&#xff08;以下简称“蓝因机器人”&#xff09;创始人陈卜铭先生来访ABeam旗下德硕管理咨询&#xff08;深圳&#xff09;有限公司&#xff08;以下简称“ABeam-SZ”&#xff09;&#xff0c;与新创部门展开合作交流。 交流中&am…

测试 mybatis 是否生效【具有增删改查的功能】

一、 1.1按 anl enter 1.2 注意点&#xff1a; test 下 与 上面的名字需保持一致 测试上面的&#xff0c;路径需保持一致&#xff0c;不一致&#xff0c;后期可能会报错。不是相同目录可能会找不到启动类 1.3 写测试 1.4.1 【先】 添加插件 【一键调用一个对象的所有的se…

C++类和对象:赋值重载,const成员,取地址及const取地址操作符重载

文章目录 1.赋值运算符重载1.1运算符重载1.2 赋值运算符重载1.3 前置和后置重载 2.日期类的实现3. const成员函数4 取地址及const取地址操作符重载 上文介绍了前三个默认成员函数&#xff0c;本文会介绍剩下三个&#xff0c; 赋值重载会重点展开。 1.赋值运算符重载 1.1运算符…

双非一战逆天改命,上岸Top3!

这个系列会邀请上岸学长学姐进行经验分享~今天经验分享的同学同样是小马哥上海交大819的全程班学员&#xff0c;双非逆袭上岸&#xff0c;非常厉害&#xff01; 01-前言 个人介绍&#xff1a;本人就读于江苏某双非&#xff0c;绩点3.2&#xff0c;本科期间仅校赛级别奖项。四…

JavaSE内部类

内部类概述 1.内部类的基础 内部类的分类&#xff1a;实例化内部类&#xff0c;静态内部类&#xff0c;局部内部类和匿名内部类 public class OutClass {// 成员位置定义&#xff1a;未被static修饰 --->实例内部类public class InnerClass1{}// 成员位置定义&#xff1a;被…

公园景区伴随音乐系统-公园景区数字IP广播伴随音乐系统建设指南

公园景区伴随音乐系统-公园景区数字IP广播伴随音乐系统建设指南 由北京海特伟业任洪卓发布于2024年4月23日 随着“互联网”被提升为国家战略&#xff0c;传统行业与互联网的深度融合正在如火如荼地展开。在这一大背景下&#xff0c;海特伟业紧跟时代步伐&#xff0c;凭借其深厚…

如何在PostgreSQL中跟踪和分析查询日志,以便于排查性能瓶颈?

文章目录 启用查询日志分析查询日志1. 查找执行时间长的查询2. 分析资源消耗3. 使用pgBadger分析4. 优化查询 示例代码结论 在PostgreSQL中&#xff0c;跟踪和分析查询日志是排查性能瓶颈的重要步骤。通过查看和分析查询日志&#xff0c;我们可以了解哪些查询在执行时遇到了问题…

17.Nacos与Eureka区别

Nacos会将服务的提供者分为临时实例和非临时实例。默认为临时实例。 临时实例跟eureka一样&#xff0c;会向注册中心报告心跳监测自己是否还活着。如果不正常了nacos会剔除临时实例。&#xff08;捡来的孩子&#xff09; 非临时实例&#xff0c;nacos会主动询问服务提供者是否…

232 基于matlab的MIMO雷达模型下一种子空间谱估计方法

基于matlab的MIMO雷达模型下一种子空间谱估计方法&#xff0c;采用过估计的方法&#xff0c;避免了信源数估计的问题&#xff0c;对数据协方差矩阵进行变换&#xff0c;构造信号子空间投影矩阵和噪声子空间投影矩阵&#xff0c;不需要像经典的MUSIC一样对其进行特征分解&#x…

BBS前后端混合项目--03

展示 static/bootstrp # bootstrap.min.css /*!* Bootstrap v3.4.1 (https://getbootstrap.com/)* Copyright 2011-2019 Twitter, Inc.* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)*//*! normalize.css v3.0.3 | MIT License | github.com/n…

Python练习03

题目 解题思路 Demo58 通过字符串切片来进行反转操作 def _reverse():"""这是一个反转整数的函数"""num input("请输入想要反转的整数")print(num[::-1]) 运行结果 Demo61 首先制作一个判断边长的函数&#xff0c;通过三角形两边…

vue3项目 使用 element-plus 中 el-collapse 折叠面板

最近接触拉了一个项目&#xff0c;使用到 element-plus 中 el-collapse 折叠面板&#xff0c;发现在使用中利用高官网多多少少的会出现问题。 &#xff08;1.直接默认一个展开值&#xff0c;发现时显时不显 2 . 数据渲染问题&#xff0c;接口请求了&#xff0c;页面数据不更新 …

捕捉信号的处理

文章目录 信号捕捉 信号捕捉 信号捕捉是进程从内核态返回用户态时会对信号进行检测处理。 如果信号的处理动作是用户自定义函数,在信号递达时就调用这个函数,这称为捕捉信号。由于信号处理函数的代码是在用户空间的,处理过程比较复杂,举例如下: 用户程序注册了SIGQUIT信号的处…

linux——cron定时任务

cron定时任务配置文件中可以查看一些信息 crontab就是在提交以及管理需要周期性执行的任务 定时任务具体实现需要使用crontab命令编辑对应定时任务文件 这里执行定时任务&#xff0c;每分钟创建一个文件1.txt