详解C++类对象(中篇)——超详细

news2024/10/6 16:29:55

目录

前言:类的6个默认成员函数

一, 构造函数

1. 概念

2. 特性

二, 析构函数

2.1 概念

2.2 特性

2.3 牛刀小试 

三, 拷贝构造函数

3.1概念

3. 2 特点

四, 赋值运算符重载

4. 1 运算符重载 

五, const成员函数

六,取地址及const取地址操作符重载

七,练习——实现日期计算器

结语


前言:类的6个默认成员函数

     如果一个类中什么成员都没有,简称为空类。
空类中真的什么都没有吗?并不是,任何类在什么都不写时,编译器会自动生成以下6个默认成员函数。
默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数。 

 

一, 构造函数

 1. 概念

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

2. 特性

构造函数是特殊的成员函数,需要注意的是,构造函数虽然名称叫构造,但是构造函数的主要任务并不是开空间创建对象,而是初始化对象
其特征如下:
  • 1. 函数名与类名相同
  • 2. 无返回值
  • 3. 对象实例化时编译器自动调用对应的构造函数。
  • 4. 构造函数可以重载。(后面拷贝构造函数会体现)
  • 5. 如果存在未自定义默认构造函数,编译器不再生成默认构造函数。 
无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数 只能有一个 。 注意:无参构造函数、全缺省构造函数、我们没写,编译器默认生成的构造函数,都可以认为是默认构造函数。

下面是一段自定义构造函数的:

#include <iostream>
using namespace std;
class Date
{
public:
	Date(int year = 2023, int month = 5, int day = 9) // 自定义默认构造函数,设置全缺省参数,对数据进行初始化。
	{
		_year = year;
		_month = month;
		_day = day;
	}

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

int main()
{
	Date z;
	Date z1(2012, 12, 12); // 由于我们自定义构造函数支持带参数设置数据初始化。
	// 接下来,我们注释掉自定义默认构造函数,来测试一下编译器默认自动生成的构造函数。
}

 当我们注释掉我们自定义的构造函数时,我们会发现z对象 的类成员变量,依旧是随机值。这里我们不禁会想,编译器自动生成的默认构造函数似乎什么也没做??

解答:C++把类型分成内置类型(基本类型)和自定义类型。
  • 内置类型就是语言提供的数据类型,如:int/char...;
  • 自定义类型就是我们使用class/struct/union等自己定义的类型。 
看看下面的程序,就会发现编译器生成默认的构造函数会对自定类型成员_t调用的它的默认成员函数。

#include <iostream>
using namespace std;
class Date
{
public:
	Date(int year = 2023, int month = 5, int day = 9) // 自定义默认构造函数,设置全缺省参数,对数据进行初始化。
	{
		_year = year;
		_month = month;
		_day = day;
	}

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

class Time
{
public:
	Date _t;      // 自定义类型

private:          // 内置类型
	int _hour;
	int _minute;
	int _second;
};
int main()
{
	Time k;
}

调试结果如下: 

  特点:

1. 内置函数不做处理。

2. 自定义类型会调用(自定义类型的)默认构造函数。

注意:C++11 中针对内置类型成员不初始化的缺陷,又打了补丁,即:内置类型成员变量在类中声明时可以给默认值

这里我们就有了两种内置成员初始化的方法: 

  • 1. 通过C++补丁初始化;()
  • 2. 自定义默认构造函数,同时给缺省参数。

二, 析构函数

2.1 概念

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

2.2 特性

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

 首先我们来看下面代码:

#include <iostream>
using namespace std;
class Date
{
public:
	Date(int year = 2023, int month = 5, int day = 9)  // 默认构造函数
	{
		_year = year;
		_month = month;
		_day = day;
	}

	~Date()   // 默认析构函数
	{
		_year = _month = _day = 0;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date z;
	return 0;
}

我们将显式析构函数注释掉,让我们测试一下编译器自动生成的默认析构函数的结果,下面的程序我们会看到:编译器生成的默认析构函数,对自定类型成员调用它的析构函数。

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

	~Date()
	{ 
		cout << "~Date()" << endl;   // 对调用Date的析构函数进行标记
		_year = _month = _day = 0;
	}
private:
	int _year;
	int _month;
	int _day;
};

class Time
{
public:
	Date _t;      // 自定义类型
	~Time()
	{
		cout << "~Time()" << endl; // 对调用Time的析构函数进行标记
	}
private:          // 内置类型
	int _hour = 10;
	int _minute = 10;
	int _second = 10;
};

void func()
{
	Time z;
}
int main()
{
	func();
	return 0;
}

 结果可以看出:

2.3 牛刀小试 

看下面代码,输出顺序是什么? 

class A
{
public:
	A(int a = 0)
	{
      _a = a;
		cout << "A(int a = 0)->" <<_a<< endl;
	}

	~A()
	{
		cout << "~A()->" <<_a<<endl;
	}
private:
	int _a;
};

A aa3(3);

void f()
{
	static int i = 0;
	static A aa0(0);
	A aa1(1);
	A aa2(2);
	static A aa4(4);
}

// 构造顺序:3 0 1 2 4 1 2
// 析构顺序:~2 ~1 ~2 ~1 ~4 ~0 ~3
int main()
{
	f();
	f();
	return 0;
}

核心思路:遵循栈的思路,先进后出

三, 拷贝构造函数

 3.1概念

在现实生活中,可能存在一个与你一样的自己,我们称其为双胞胎。 

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

3. 2 特点

拷贝构造函数也是特殊的成员函数,其特征如下:
  • 1. 拷贝构造函数是构造函数的一个重载形式
  • 2. 拷贝构造函数的参数只有一个必须是类类型对象的引用,使用传值方式编译器直接报错,因为会引发无穷递归调用。

下面是会发生无穷递归代码:

class Date
{
public:
	Date(int year = 2023, int month = 5, int day = 9)
	{
		_year = year;
		_month = month;
		_day = day;
	}

	Date(Date b1)  // 正确代码:Date(Date& b1)
	{
		_year = b1._year;
		_month = b1._month;
		_day = b1._day;
	}
private:
	int _year;
	int _month;
	int _day;
};

无穷递归如图:

 换成类类型引用即可解决无穷递归的问题。 

class Time
{
public:
	Time(int hour = 1 , int minute = 2, int second = 3)
	{
		_hour = hour;
		_minute = minute;
		_second = second;
	}

	Time(const Time& a)
	{
		_hour = a._hour;
		_minute = a._minute;
		_second = a._second;
		cout << "Time(Time& a)" << endl;
	}

	~Time()
	{
		cout << "~Time()" << endl;
	}
private:        
	int _hour;
	int _minute;
	int _second;
};

class Date
{
public:
	Date(int year = 2023, int month = 5, int day = 9)
	{
		_year = year;
		_month = month;
		_day = day;
	}

	Date(const Date& b1)  // 正确代码:Date(Date& b1)
	{
		_year = b1._year;
		_month = b1._month;
		_day = b1._day;
	}

	Time _t;
private:
	int _year;
	int _month;
	int _day;
};
void func()
{
	Date z;
	Date k(z);
}

int main()
{
	func();
	return 0;
}
在编译器生成的默认拷贝构造函数中,内置类型是按照字节方式直接拷贝的,而自定义类型是调用其拷贝构造函数完成拷贝的。

我们发现,编译器自动生成的拷贝构造函数,足够我们进行值拷贝,那么我们还需要自定义拷贝构造函数吗?

// 这里会发现下面的程序会崩溃掉?这里就需要我们以后讲的深拷贝去解决。
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(s1);
 return 0;
}

所以类中如果没有涉及资源申请时,拷贝构造函数是否写都可以;一旦涉及到资源申请时,需要深度拷贝,则拷贝构造函数是一定要写的,否则就是浅拷贝

四, 赋值运算符重载

4. 1 运算符重载 

C++为了增强代码的可读性引入了运算符重载运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似
函数名字为:关键字operator后面接需要重载的运算符符号
函数原型:返回值类型 operator操作符(参数列表)
注意:
  • 不能通过连接其他符号来创建新的操作符:比如operator@
  • 重载操作符必须有一个类类型参数
  • 用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不能改变其含义。
  • 作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this。
  • .*  ::   sizeof   ?:   . 注意以上5个运算符不能重载。这个经常在笔试选择题中出现。 

下面有有几个应用例子:

class Time
{
public:
	Time(int hour = 1 , int minute = 2, int second = 3)
	{
		_hour = hour;
		_minute = minute;
		_second = second;
	}

	Time(const Time& a)
	{
		_hour = a._hour;
		_minute = a._minute;
		_second = a._second;
		cout << "Time(Time& a)" << endl;
	}

	bool operator==(const Time& a)   
	{
		return _hour == a._hour &&
			_minute == a._minute &&
			_second == a._second;
	}

	bool operator>(const Time& a)
	{
		return _hour > a._hour &&
			_minute > a._minute &&
			_second > a._second;
	}

   Time& operator=(const Time& a)   // 内成员赋值运算符重载
	{
		_hour = a._hour;
		_minute = a._minute;
		_second = a._second;
		return *this;
	}
	
    ~Time()
	{
		cout << "~Time()" << endl;
	}
private:        // 内置类型
	int _hour;
	int _minute;
	int _second;
};

这里对赋值运算符进行补充;

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

原因:赋值运算符如果不显式实现,编译器会生成一个默认的。此时用户再在类外自己实现一个全局的赋值运算符重载,就和编译器在类中生成的默认赋值运算符重载冲突了,故赋值运算符重载只能是类的成员函数
2.用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝。注意:内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值。
既然编译器生成的默认赋值运算符重载函数已经可以完成字节序的值拷贝了,还需要自己实现吗?当然像日期类这样的类是没必要的。那么下面的类呢?验证一下试试?
// 这里会发现下面的程序会崩溃掉?这里就需要我们以后讲的深拷贝去解决。
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成员函数

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

让我们看看下面的实例代码吧:

class moss
{
public:
	moss(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;
	}
	void Print() const  // 这就是const成员函数,同上面的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; // 日
};
void Test3()
{
	moss d1(2022, 1, 13);
	d1.Print();
	const moss d2(2022, 1, 13);
	d2.Print();
}

 首先我们已经知道const具有限制权限的功能,比如 int this,如图:

 对本次事例解析:

六,取地址及const取地址操作符重载

这个比较容易理解,这两个默认成员函数一般不用重新定义 ,编译器默认会生成。 看下面代码:

class Date
{ 
public :
 Date* operator&()
 {
 return this ;
 }
 const Date* operator&()const
 {
 return this ;
 }
private :
 int _year ; // 年
 int _month ; // 月
 int _day ; // 日
};
这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可,只有特殊情况,才需要重载,比如想让别人获取到指定的内容!

七,练习——实现日期计算器

用C++类编写一个日期计算器,利用今天的运算符重载知识,实现日期+天数,日期-天数,日期-日期的功能。

下面是代码分享:

头文件:

#pragma once

#include<iostream>
using namespace std;
#include <assert.h> 

class Date
{
public:
	// 获取某年某月的天数
	int GetMonthDay(int year, int month)
	{
		// 因为需要频繁调用,所以写成内联函数。
		static int M[13] = { 0,31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
		int day = M[month];
		if (month == 2 &&
			((year % 4 == 0 && year % 100 != 0) ||
				(year % 400 == 0)))
		{
			day++;
		}
		return day;
	}
	// 全缺省的构造函数
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;

		if (!CheckDate())
		{
			cout << "非法日期" << endl;
			exit(-1);
		}
	}

	bool CheckDate()
	{
		if (_month > 12 || _day > GetMonthDay(_year, _month))
		{
			return false;
		}
		else
		{
			return true;
		}
	}
	// 拷贝构造函数
    // d2(d1)
	Date(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}

	// 赋值运算符重载
  // d2 = d3 -> d2.operator=(&d2, d3)
	Date& operator=(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
		return *this;
	}
	// 析构函数, 全是内置函数,没什么好清理的,调用编译器自动生成的就行。
	~Date()
	{
		;
	}
		
	// 日期+=天数
	Date& operator+=(int day);
	// 日期+天数
	Date operator+(int day);
	// 日期-天数
	Date operator-(int day);
	// 日期-=天数
	Date& operator-=(int day);
	// 前置++
	Date& operator++();
	// 后置++
	Date operator++(int);
	// 后置--
	Date operator--(int);
	// 前置--
	Date& operator--();
	// >运算符重载
	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);
	// 日期-日期 返回天数
	int operator-(const Date& d);

	int WeekDay()
	{
		Date start(1, 1, 1);
		int LeveDay = 1;
		int day = (*this - start);
		LeveDay += day;
		int WeekDay = LeveDay % 7;
		return WeekDay;
	}
	// 友元函数为外边全局函数拥有调用类成员的权限。
	friend ostream& operator<<(ostream& cou, const Date& a);
	friend istream& operator>>(istream& cin, Date& a);

	void Print()const  // 本身是 Date* const this--是不能修改其指向的this,
		//但可以修改其内容,为了能接受被const Date* const this的对象所以需要缩小权限(方法就是函数名后加const)
		//反正print函数没有修改功能。
	{
		cout << _year << endl;
		cout << _month << endl;
		cout << _day << endl;
	}

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

// 放在全局中可以外部调用重载后的运算符,但放在外面又不能访问类成员,这里会用到后面的友元函数。
// 重载cout输出流
inline ostream& operator<<(ostream& cou,  const Date& a)
{
	cou << a._year << "年" << a._month << "月" << a._day << "日";
	return cou;
}

// 重载cint提取流
inline istream& operator>>(istream& cin, Date& a)
{
	cin >> a._year >> a._month >> a._day;
	assert(a.CheckDate());
	return cin;
}

函数实现源文件:

#define _CRT_SECURE_NO_WARNINGS 1
#include"Date.h"

// 日期+=天数
Date& Date::operator+=(int day)
{
	_day += day;
		while ( Date::GetMonthDay(_year, _month) < _day)
		{
			_day -= Date::GetMonthDay(_year, _month);
			_month++;

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

// 日期+天数     让我们得出结果的临时拷贝,所以可以复用+= ,
// 但有一个缺点是,日期其实已经被污染,不能在原日期下重新调用。
Date Date::operator+(int day)
{
	*this += day;
	Date tmp = *this;
	return tmp;
}


// 日期-天数  //可以复用 -= ,但原日期被修改。
Date Date::operator-(int day)
{
	*this -= day;
	Date tmp = *this;
	return tmp;
}
// 日期-=天数
Date& Date::operator-=(int day)
{
	_day -= day;
	while (_day <= 0)
	{
		_month--;   // 如果_month == 0了,就提取不了对应月份的天数
		if (_month == 0)
		{
			_year--;
			_month = 12;
		}
		_day += Date::GetMonthDay(_year, _month);
	}
	return *this;
}

// 前置++  加完后返回
// 为了区分重载函数前置与后置++,C++做了重载区分,就是后置++增加一个int参数。
Date& Date::operator++()
{
    // 可以进行复用+=
	* this += 1;
	return *this;
}

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

// 后置--
Date Date::operator--(int)
{
	Date tmp(*this);
	*this -= 1;
	return tmp;
}
// 前置--
Date& Date::operator--()
{
	*this -= 1;
	return *this;
}
// // >运算符重载
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 _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)
{
	if ((_year < d._year) ||
		((_year <= d._year) && (_month < d._month)) ||
		((_year <= d._year) && (_month <= d._month) && _day < d._day))
	{
		return true;
	}
	else
	{
		return false;
	}
}
// <=运算符重载
bool Date::operator <= (const Date& d)
{
	return (*this < d) || (*this == d);
}
// !=运算符重载
bool Date::operator != (const Date& d)
{
	return _year != d._year &&
		_month != d._month &&
		_day != d._day;
}

// 日期-日期 返回天数  思路:用小的加到大的,计算中间的次数。
int Date::operator-(const Date& d)
{
	int flog = 1;
	Date a1(*this); // 假设a1大
	Date a2(d);
	if (a1 < a2)    // a1小替换为a2
	{
		a1 = d;
		a2 = *this;
		flog = -1;
	}
	int n = 0;
	while (a2 < a1)
	{
		/*if (a2._day == 9 && a2._month == 5)
		{
			int x = 0;
		}*/
		++a2;
		n++;
	}
	return n * flog;
}

测试源文件:

#define _CRT_SECURE_NO_WARNINGS 1

#include"Date.h"

void Test()
{
	const char* WeekRoom[7] = { "周天", "周一", "周二", "周三", "周四", "周五", "周六" };
   
	do
	{
	cout << "------------------------------------" << endl;
	cout << "--------请输入要操作的选项----------" << endl;
	cout << "----1. 日期+天数---2.日期-天数----" << endl;
	cout << "----3. 日期-日期---0.结束程序 --------" << endl;
	cout << "----4.  --------" << endl;
	int opertaton = 0;
	cin >> opertaton;
	Date a1, a2;
	int day;
	switch (opertaton)
	{
	case 1: 
		cout << "-----------"<< endl;
		cin >> a1 >> day;
		cout << (a1 += day) << endl;
		cout << WeekRoom[a1.WeekDay()] << endl;
		break;
	case 2:
		cout << "-----------" << endl;
		cin >> a1 >> day;
		cout << (a1 -= day) << endl;
		cout << WeekRoom[a1.WeekDay()] << endl;
		break;
	case 3:
		cout << "-----------" << endl;
		cin >> a1 >> a2;
		cout << (a1 - a2);
		break;
	case 0:
		cout << "结束程序";
		exit(-1);
	default:
		break;
	}
	} while (true);
}

int main()
{
	Test();
	return 0;
}

结语

本小节就到这里了,感谢小伙伴的浏览,如果有什么建议,欢迎在评论区评论;如果给小伙伴带来一些收获请留下你的小赞,你的点赞和关注将会成为博主创作的动力。

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

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

相关文章

【Redis高级应用】最佳实践

文章目录 Redis键值设计优雅的key结构拒绝BigKeyBigKey的危害如何发现BigKey如何删除BigKey 恰当的数据类型总结 批处理优化Pipeline我们的客户端与redis服务器是这样交互的MSetPipeline 集群下的批处理串行化执行代码实践 服务器端优化-持久化配置服务器端优化-慢查询优化什么…

Maven构建学习

目录 nacos是用来干什么的 Maven构建生命周期 Clean 生命周期 nacos是用来干什么的 在 Maven 项目中&#xff0c;pom.xml 文件中包含了项目的基本信息&#xff0c;通常包括&#xff1a; 能分别解释一下这里的 、、 maven-antrun-plugin分别起什么作用吗&#xff1f; rocke…

是德MSOX4104A 数字存储示波器

4000 X 系列拥有一系列引以为傲的配置&#xff0c;包括采用了电容触摸屏技术的 12.1 英寸显示屏、InfiniiScan 区域触摸触发、100 万波形/秒捕获率、MegaZoom IV 智能存储器技术和标配分段存储器。 MSOX4104A数字存储示波器 主要特性与技术指标 体验超凡速度&#xff1a; •1…

MQTT服务器搭建流程-QT开发客户端

目录 一、环境准备 二、客户端开发 2.1 下载并且编译MQTT 2.2 客户端开发准备 2.3 客户端开发源码 三、测试演示 一、环境准备 操作系统&#xff1a;centos7.5 链接: https://pan.baidu.com/s/1BRYQ13RTIgkyD0GDsXB1jQ 提取码: 29e2 MQTT服务器 使用EMQX作为服务器 安…

SpringCloud Alibaba 服务注册

一、SpringCloud Alibaba简介 Spring官网&#xff1a;https://spring.io/projects/spring-cloud-alibabaGitHub&#xff1a;https://github.com/alibaba/spring-cloud-alibabaGitHub中文文档&#xff1a;https://github.com/alibaba/spring-cloud-alibaba/blob/master/README-…

AFG1062任意波形/函数发生器 产品资料

AFG1000 任意波形/函数发生器&#xff0c;提供 25MHz 或 60MHz 带宽&#xff0c;2 个输出通道&#xff0c;在整个带宽内 1mVpp 到 10Vpp 输出振幅&#xff0c;泰克 AFG1000 任意波形/函数发生器可以生成各种实验室测试所需波形。 *重要的是&#xff0c;它在泰克任意函数发生器系…

卫龙上市后首份财报:营收净利双降、去年净利下滑8成

当你吃辣条的时候&#xff0c;你在吃什么&#xff1f; 味道&#xff1f;口感&#xff1f;还是童年的记忆&#xff1f; 近日&#xff0c;卫龙美味全球控股有限公司&#xff08;下称“卫龙”&#xff09;发布了上市后的首份年报。 卫龙是一家辣味休闲食品的企业&#xff0c;根…

portraiture插件下载安装PS磨皮滤镜插件

coco玛奇朵是讲磨皮插件的安装和使用方法&#xff0c;用的PS版本是PS2023版&#xff0c;不用你学很复杂的高低频磨皮美白祛痘技术&#xff0c;也不需要懂什么是ps磨皮中性灰&#xff0c;也不用各种骚操作&#xff0c;只需要一键就能磨皮。对于摄影爱好者来说&#xff0c;他真的…

微服务架构路线

一、我为什么选择微服务架构&#xff1f; 众所周知&#xff0c;单体应用程序&#xff0c;由于其种种不足&#xff0c;几乎不支持敏捷方法。如果你想为一个大型或复杂的业务创建一个软件项目&#xff0c;最好从微服务架构开始。 微服务架构是一种灵活的架构&#xff0c;可以显著…

【python 多线程】零基础也能轻松掌握的学习路线与参考资料

Python 多线程指的是在同一时间内&#xff0c;Python 程序中存在多个线程同时执行的情况。Python 中的线程是轻量级的&#xff0c;由操作系统进行调度和处理。多线程的学习对于想要进行 Python 并发编程的程序员来说是非常重要的。本文将提供 Python 多线程的学习路线、参考资料…

Talk预告 | 港中文博士生赖昕:SphereFormer大幅提升LiDAR点云远处识别性能

本期为TechBeat人工智能社区第496期线上Talk&#xff01; 北京时间5月11日(周四)20:00&#xff0c;香港中文大学三年级博士生—赖昕的Talk将准时在TechBeat人工智能社区开播&#xff01; 他与大家分享的主题是: “SphereFormer大幅提升LiDAR点云远处识别性能”&#xff0c;届时…

Talk预告 | 大连理工大学IIAU Lab在读博士生严彬:走向通用实例感知

本期为TechBeat人工智能社区第495期线上Talk&#xff01; 北京时间5月10日(周三)20:00&#xff0c;大连理工大学IIAU Lab在读博士生—严彬的Talk将准时在TechBeat人工智能社区开播&#xff01; 他与大家分享的主题是: “走向通用实例感知”&#xff0c;届时将介绍和探讨通用实…

Nginx从入门到精通

一、 Nginx能做什么 1.反向代理 2.负载均衡 3.HTTP服务器&#xff08;包含动静分离&#xff09; 4.正向代理 例如&#xff1a; 我当前配置的服务器 1、配置http 2、配置https 3、配置反向代理 [rootasia~]# cat /etc/nginx/nginx.conf # For more information on configur…

【Java零基础入门篇】第 ④ 期 - 继承(一)

【Java零基础入门篇】第 ④ 期 - 继承&#xff08;一&#xff09; 博主&#xff1a;命运之光专栏&#xff1a;Java零基础入门 学习目标 1.掌握继承性的主要作用、实现、使用限制&#xff1b; 2.掌握this和super的含义及其用法&#xff1b; 3.掌握方法覆写的操作&#xff1b; 4.…

windows环境安装使用nginx,redis详解

01-redis windows版下载地址&#xff1a; Releases microsoftarchive/redis GitHub 直接运行.msi的安装包&#xff0c;一直next&#xff0c;直到下面界面,勾选上再next 这一步选择端口&#xff0c;然后next&#xff08;后面可以通过配置文件修改的&#xff09; 选择最大缓存容…

哪种款式蓝牙耳机戴着舒服?公认佩戴舒适度高的蓝牙耳机

真无线蓝牙耳机具有使用方便、随身携带&#xff0c;一跃成为蓝牙耳机行业的新宠&#xff0c;几乎是人手必备的数码单品&#xff0c;耳机市场十分庞大&#xff0c;让消费者很难抉择到底蓝牙耳机哪个品牌最好&#xff0c;所以下面就介绍几款佩戴舒适度高的蓝牙耳机&#xff0c;分…

快递从揽收到仓库出仓之间的时间差,要如何分析

最近很多朋友跟我说最近在工作碰到这个样的问题&#xff0c;让他一直都很困扰着&#xff0c;不知道要如何解决呢&#xff0c;很多平台有规定&#xff0c;快递从揽收到仓库出仓这个时间&#xff0c;如果超出平台规定时内快递还没出仓库&#xff0c;平台算您违规&#xff0c;会对…

一种有效的水下无线传感器网络路由协议(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 与陆地多跳传感器网络类似&#xff0c;水下网络的路由协议可以分为&#xff1a;①主动路由&#xff0c;②按需路由。 ①主动路…

中创 | 云服务市场竞争加剧,全国增值电信业务经营许可企业达14万家

中国互联网行业的竞争愈加激烈&#xff0c;都试图在市场中获取优势&#xff0c;寻求新的发展蓝海。其中&#xff0c;在数字经济中扮演重要角色的云服务产业&#xff0c;如今也处于一个前所未有的大变局。 但想要进入云服务产业&#xff0c;“证件”和“技术”一样都不能少&…

基于FPGA的VGG16卷积神经网络加速器

文章搬运自本人知乎 VGG16网络结构介绍 VGG在2014年由牛津大学Visual GeometryGroup提出&#xff0c;获得该年lmageNet竞赛中Localization Task(定位任务)第一名和 Classification Task (分类任务)第二名。与AlexNet相比&#xff0c;VGG使用了3个3x3卷积核来代替7x7卷积核&…