【C++】类的6个默认成员函数

news2024/12/26 23:50:19

目录

1. 类的6个默认成员函数

2. 构造函数

3. 析构函数

4. 拷贝构造函数

5. 运算符重载

5.1运算符重载

5.2赋值运算符重载

 5.3前置++和后置++重载

5.4日期类的实现

6. const成员函数

7. 取地址及const取地址操作符重载


1. 类的6个默认成员函数

对于一个空类,编译器会自动生成以下6个默认成员函数

2. 构造函数

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

构造函数的主要任务不是开空间创建对象而是初始化对象

构造函数的特性:

1️⃣函数名和类名相同

2️⃣无返回值

3️⃣对象实例化时编译器自动调用对应的构造函数

4️⃣构造函数可以重载

调用无参构造函数初始化对象时,对象后面不用跟括号,否则会和函数声明混淆;

5️⃣如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义则编译器不再自动生成

编译器生成的默认构造函数:

在上面的日期类中,我们创建了一个对象,通过默认构造函数初始化后,_year,_month,_day中仍是随机值,那编译器生成的默认构造函数的意义是什么呢?

C++中把类型分成内置类型(基本类型)和自定义类型。内置类型就是语言提供的数据类型,如int、char等;自定义类型就是我们使用关键字class/struct/union等自己定义的类型。编译器生成的默认构造函数会对自定义类型成员调用它的默认构造函数,而内置类型不作处理,C++11中,针对内置类型成员不初始化的缺陷,打了补丁:内置类型成员变量在类声明时可以给默认值

定义如下一个类: 

class Time
{
public:
	Time()
	{
		cout << "调用构造函数Time()" << endl;
		_hour = 0;
		_minute = 0;
		_second = 0;
	}
private:
	int _hour;
	int _minute;
	int _second;
};

在日期类中添加我们自定义类型的一个成员变量_time,调试可以发现,创建一个对象时,会调用自定义类型成员变量的构造函数,完成初始化。

内置类型成员变量在类声明时可以给默认值

实际上这种方式是给内置类型的成员变量一个缺省值

内置类型的成员变量初始化: 

6️⃣无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认的构造函数只能有一个,若存在多个,则调用时存在二义性。无参构造函数全缺省的构造函数编译器默认生成的构造函数,都可以认为是默认构造函数

默认构造函数不传参就可以调用的构造函数

3. 析构函数

析构函数和构造函数的功能相反,对象在销毁时会自动调用析构函数,完成对象中资源的清理工作。析构函数不是完成对对象本身的销毁,局部对象的销毁工作是由编译器完成的

析构函数的特性:

1️⃣析构函数名是在类名前加上~

2️⃣无参数无返回值类型,因此析构函数不支持重载

3️⃣一个类只能有一个析构函数,若未显式定义,则编译器会自动生成默认的析构函数

4️⃣对象的生命周期结束时,系统自动调用析构函数

5️⃣编译器生成的默认析构函数,对自定义类型成员调用它的析构函数

📖Note:

当创建的Date类对象销毁时,要保证其内部所有的成员都可以被销毁,test1函数中没有直接调用Time类的析构函数,而是调用Date类的析构函数(编译器自动生成的),Date类的析构函数中才会调用Time类的析构函数。

创建哪个类的对象则调用该类的构造函数,销毁哪个类的对象则调用该类的析构函数

6️⃣如果类中没有申请资源时,析构函数可以不写,直接使用编译器生成的默认析构函数,比如Date类;有资源申请时,需要自己写析构函数,否则会造成资源泄露,比如Stack类

4. 拷贝构造函数

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

拷贝构造函数的特性:

1️⃣拷贝构造函数是构造函数的一个重载形式

2️⃣拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值传参的方式编译器会直接报错,因为会引发无穷递归调用(一次传值传参就调用一次拷贝构造)

传值传参引发的无穷递归调用

函数调用时,形参是实参的一份临时拷贝,在传值传参的过程中,会产生一个临时中间变量,先将d1拷贝给这个临时变量,这次拷贝会调用拷贝构造函数,而拷贝构造函数的传传参方式是传值传参,所以每次调用拷贝构造都会产生临时变量,调用拷贝构造函数,因此引发了无穷的函数调用。传参过程如下图:

 

3️⃣若未显式定义,编译器会自动生成默认的拷贝构造函数。默认的拷贝构造函数对内置类型的成员变量按内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝;对自定义类型的成员变量通过调用其拷贝构造函数完成拷贝

class Stack
{
public:
	//构造函数
	Stack(size_t capacity = 10)
	{
		_array = (DataType*)malloc(sizeof(DataType) * capacity);
		if (nullptr == _array)
		{
			perror("malloc failed");
			return;
		}
		_capacity = capacity;
		_top = 0;
	}
	//析构函数
	~Stack()
	{
		if (_array)
		{
			free(_array);
			_array = nullptr;
			_capacity = 0;
			_top = 0;
		}
	}

	//压栈
	void Push(const DataType& data)
	{
		//扩容
		CheckCapacity();
		_array[_top] = data;
		++_top;
	}

private:
	//扩容
	void CheckCapacity()
	{
		//栈满
		if (_top == _capacity)
		{
			int newcapacity = _capacity * 2;
			DataType* tmp = (DataType*)realloc(_array, newcapacity * sizeof(DataType));
			if (tmp == NULL)
			{
				perror("realloc failed\n");
				return;
			}
			_array = tmp;
			_capacity = newcapacity;
		}
	}
private:
	//变量定义
	DataType* _array;
	size_t _capacity;
	size_t _top;
};

如上图,当我们没有显式定义拷贝构造函数,使用系统自动生成的拷贝构造函数时,对于栈类,一次拷贝构造后,栈s1和栈s2指向了同一块内存空间

程序退出时,栈s1和栈s2需要销毁,后定义变量的先销毁,即s2先销毁,调用析构函数,将这块内存空间释放,s2再销毁,调用析构函数,也要释放这块空间,但此时这块空间已经被释放了,因此程序会崩溃

以上过程是一次浅拷贝的过程;对于栈类,需要显式定义拷贝构造函数以实现深拷贝,即使用栈s1拷贝构造栈s2时,需要开辟和s1相同大小的空间,并将s1中的值拷贝过来,这样栈s1和栈s2都拥有自己的空间,二者相互独立,不影响后续的操作

📖Note:

类中如果没有涉及资源申请时,拷贝构造函数可以不显式定义,如日期类;一旦类中涉及资源申请,则一定要显式定义拷贝构造函数,否则拷贝就是浅拷贝,如栈

总结:需要写析构函数的类,都要显式定义深拷贝的拷贝构造函数,其他类使用默认生成的拷贝构造函数即可

4️⃣拷贝构造函数典型的调用场景

  • 使用已存在对象创建新对象(上述例子)
  • 函数参数类型为类类型对象
  • 函数返回值类型为类类型对象

总结:

为了提高程序效率,对象传参时尽量使用引用传参,返回时根据实际情况尽量使用引用返回

5. 运算符重载

5.1运算符重载

C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数

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

📖Note:

  1. 不能通过连接其他符号来创建新的操作符,如operator@
  2. 重载操作符必须有一个类类型参数
  3. 用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不能改变其含义
  4. 作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this指针
  5. 不能重载的5个运算符:⑴ .*  、⑵ ::   、 ⑶sizeof  、⑷? :  、⑸​​​​​​​​​​​​​​ .

操作符==的重载 

全局的operator==存在的问题:私有的成员变量不能访问;如果将成员变量设置成公有的,则封装性不能保证

解决方案:

  1. 直接重载成成员函数
  2. 定义一个公有的成员函数GetYear(),获取私有的成员变量
  3. 使用友元

1️⃣直接重载成成员函数

此时形参列表中只需要显式定义一个参数,因为第一个参数为隐含的this指针

//日期类
class Date
{
public:
    //操作符==重载
	bool operator==(const Date& d)
	{
		return _year == d._year
			&& _month == d._month
			&& _day == d._day;
	}
	
private:
	int _year;
	int _month;
	int _day;
};

2️⃣定义一个公有的成员函数GetYear(),获取私有的成员变量

注意获取成员函数的函数需要用const修饰

//日期类
class Date
{
public:
	//获取私有成员函数
	int GetYear(const Date& d) const
	{
		return d._year;
	}
	int GetMonth(const Date& d) const
	{
		return d._month;
	}
	int GetDay(const Date& d) const
	{
		return d._day;
	}
	
private:
	int _year;
	int _month;
	int _day;
};
//全局的operator==
bool operator==(const Date& d1,const Date& d2)
{
	return d1.GetYear(d1) == d2.GetYear(d2)
		&& d1.GetMonth(d1)== d2.GetMonth(d2)
		&& d1.GetDay(d1) == d2.GetDay(d2);
}

int main()
{
	Date d1(2024, 2, 9);
	Date d2(2024, 2, 10);

	cout << (d1 == d2) << endl; //输出0

	return 0;
}

3️⃣使用友元

//日期类
class Date
{
public:
	//全缺省的构造函数
	Date(int year = 2024, int month = 2, int day = 8)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	//拷贝构造
	Date(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}

	//声明全局的operator==为友元函数
	friend bool operator==(const Date& d1, const Date& d2);
	
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;
}

5.2赋值运算符重载

1️⃣赋值运算符重载格式:

  • 参数类型:const T&,引用传参可以提高传参效率(T表示数据类型)
  • 返回值类型:T&,引用返回可以提高返回的效率,有返回值的目的是为了支持连续赋值
  • 检测是否自己给自己赋值
  • 返回*this:要符合连续赋值的含义
//日期类
class Date
{
public:
	//全缺省的构造函数
	Date(int year = 2024, int month = 2, int day = 8)
	{
		_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;
	}
	//打印
	void print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
	
private:
	int _year;
	int _month;
	int _day;
};

赋值运算符重载:

参数列表中,只写了一个参数,实际上有两个参数,第一个参数是隐含的this指针,赋值操作符需要区分左右操作数,第一个参数是左操作数,第二个参数是右操作数

返回值:this指针是左操作数的地址,返回*this,即左操作数的值,除了赋值重载函数的作用域,左操作数这个对象还在,因此可以采用引用返回,避免一次拷贝构造,提高效率

返回值的类型是类类型,不需要加const,因为可能会对返回值做修改

 

连续赋值的情况:上述代码中,先执行d5 = d4,调用赋值重载,d5=d4转换为Date& operator (&d5,&d4),把d4的值拷贝给d5,并返回左操作数d5,因此d5 = d4这个表达式的值为d5,因此接下来执行的就是d6 = d5,即把d5的值拷贝给d6,和上述同样的操作,完成了一次连续赋值

2️⃣赋值运算符只能重载成类的成员函数而不能重载成全局函数

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

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

📖Note:

内置类型的成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值

栈的赋值重载:拷贝构造不能完成使用一个栈初始化另一个栈的操作,因为拷贝构造使两个栈指向了同一块空间,程序运行结束时析构两次会导致程序崩溃

当我们没有显式定义赋值运算符重载时,使用编译器在类内生成的默认赋值运算符重载,以值的方式逐字节拷贝每个成员变量的值,由上图,两个栈赋值时会发生错误

以值的方式逐字节拷贝,会导致栈s1和栈s2中的指针同时指向s2指向的空间,而原来s1指向的空间并没有释放,导致了内存泄漏;同时指向的这同一块空间会在程序结束时被析构两次

解决方案:在栈类内显式定义赋值运算符重载,为两个栈开辟不同的空间,使二者的结构独立

Stack& operator=(const Stack& st)
{
	if (this != &st)
	{
		free(_array);//释放原来空间
		_array = (DataType*)malloc(sizeof(DataType) * st._capacity);
		if (_array == nullptr)
		{
			perror("malloc failed");
			exit(-1);
		}
		memcpy(_array, st._array, sizeof(DataType) * st._top);
		_top = st._top;
		_capacity = st._capacity;
	}
	return *this;
}

if语句的作用是避免同一个栈自己给自己赋值

释放被赋值的对象原来空间后,开辟和右操作数对应的栈相同大小的空间,并将栈中的数据拷贝过去,就实现了两个栈独立存在

返回*this是为了可以实现连续的赋值操作

 5.3前置++和后置++重载

前置++:先++后使用 ===>返回值是++后的值

this指向的对象函数结束后不会销毁,因此可以使用引用返回

后置++:先使用后++ ===>返回值是++前的值

前置++和后置++都是一元运算符,为了使前置++和后置++能正确重载,C++规定:后置++运算符重载时多增加一个int类型的参数,但调用函数时该参数不用传递,由编译器自动传递。后置++要返回旧值,因此需要创建临时变量存储++前的值,最终返回的也是旧值,因为旧值存放在临时变量中,因此只能传值返回,不能引用返回

//日期类
class Date
{
public:
	//构造函数
	Date(int year = 2024, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	//打印
	void print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
	//前置++
	Date& operator++()
	{
		_day += 1;
		return *this;
	}

	//后置++
	Date operator++(int)
	{
		Date tmp(*this);//拷贝构造,存储++前的数据
		_day += 1;
		return tmp;
	}

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

📖Note:

对于后置++来说,它比前置++多了两次拷贝,一次调用拷贝构造,一次传值返回;因此对于自定义类型的变量,尽量使用前置++

前置--和后置--的实现和++类似

//前置--
Date& operator--()
{
	_day -= 1;
	return *this;
}

//后置--
Date operator--(int)
{
	Date tmp(*this);//拷贝构造,存储++前的数据
	_day -= 1;
	return tmp;
}

5.4日期类的实现

//日期类
class Date
{
public:

	Date(int year = 2024, int month = 2, int day = 6)
	{
		_year = year;
		_month = month;
		_day = day;
		//cout << "调用构造函数" << endl;
	}
	//拷贝构造函数
	Date(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
		//cout << "调用拷贝构造函数" << endl;
	}
	//析构函数
	~Date()
	{
		//cout << "调用析构函数" << endl;
	}

	//打印
	void print() const
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}

private:
	//内置类型
	int _year = 1 ;
	int _month = 1;
	int _day = 1;
};

以上是一个简单的日期类,我们已经实现类赋值运算符的重载,操作符==的重载,以下我们将实现>、>=、<、<=、+、+=、-、-=等运算符的重载

 1️⃣>和>=的重载

//>的重载
bool operator>(const Date& d)
{
	if (_year > d._year)
	{
		return true;
	}
	else if (_year == d._year && _month > d._month)
	{
		return true;
	}
	else if (_year == d._year && _month == d._month && _day > d._day)
	{
		return true;
	}
	return false;
}
//>=的重载
bool operator>=(const Date& d)
{
	return *this > d || *this == d;
}

2️⃣<和<=的重载

//<的重载
bool operator<(const Date& d)
{
	if (_year < d._year)
	{
		return true;
	}
	else if (_year == d._year && _month < d._month)
	{
		return true;
	}
	else if (_year == d._year && _month == d._month && _day < d._day)
	{
		return true;
	}
	return false;
}
//<=的重载
bool operator<=(const Date& d)
{
	return *this < d || *this == d;
}

3️⃣+和+=的重载

日期类对象的假发涉及进位问题,因为存在大月小月,平年闰年问题,我们可以使用月份数组来获取某年某个月的天数

+=等重载可以引用返回,+的重载要返回临时变量中的值,只能传值返回

//月份数组
int GetMonthDay(int year, int month)
{
	int MonthDayArrary[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;
	}
	else
	{
		return MonthDayArrary[month];
	}
}
//+=的重载
Date& operator+=(int day)
{
	_day += day;//日期+day天
	//天数超出
	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);
		_month++;
		//月份超出
		if (_month == 13)
		{
			++_year;
			_month = 1;//年满之后,置1月份
		}
	}
	return *this;
}
//+的重载
Date operator+(int day)
{
	Date ret(*this);//拷贝构造
	ret += day;
	return ret;
}

4️⃣-和-=的重载:类似于+和+=,不够减则借位

//-=的重载
Date& operator-=(int day)
{
	_day -= day;//日期+day天
	//本月天数不够减,需要借位
	while (_day < 0)
	{
		--_month;
		//本年月数不够减,需要借位
		if (_month == 0)
		{
			--_year;
			_month = 12;//新的一年
		}
		_day += GetMonthDay(_year, _month);
	}
	return *this;
}
//-的重载
Date operator-(int day)
{
	Date ret(*this);//拷贝构造
	ret -= day;
	return ret;
}

+=、+、-、-=重载的完善:当某个日期加的天数是一个负数时,需要对这种情况进行处理,加一个负数就是减去这个负数的相反数(一个正数),调用减法的重载即可;当某个日期减的天数是一个负数时,相当于加去这个负数的相反数(一个正数),调用加法的重载即可;


//+=的重载
Date& operator+=(int day)
{
	//加一个负数===>减其相反数
	if (day < 0)
	{
		return *this -= abs(day);
	}
	_day += day;//日期+day天
	//天数超出
	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);
		_month++;
		//月份超出
		if (_month == 13)
		{
			++_year;
			_month = 1;//年满之后,置1月份
		}
	}
	return *this;
}
//+的重载
Date operator+(int day)
{
	Date ret(*this);//拷贝构造
	//加一个负数===>减其相反数
	if (day < 0)
	{
		ret -= abs(day);
		return ret;
	}
	ret += day;
	return ret;
}

//-=的重载
Date& operator-=(int day)
{
	//减一个负数 ===>加其相反数
	if (day < 0)
	{
		return *this += abs(day);
	}
	_day -= day;//日期+day天
	//本月天数不够减,需要借位
	while (_day < 0)
	{
		--_month;
		//本年月数不够减,需要借位
		if (_month == 0)
		{
			--_year;
			_month = 12;//新的一年
		}
		_day += GetMonthDay(_year, _month);
	}
	return *this;
}
//-的重载
Date operator-(int day)
{
	Date ret(*this);//拷贝构造
	//减一个负数 ===>加其相反数
	if (day < 0)
	{
		ret += abs(day);
		return ret;
	}
	ret -= day;
	return ret;
}

6. const成员函数

const成员函数:将const修饰的成员函数称为const成员函数,const修饰类成员函数,实际修饰的是该成员函数隐含的this指针,表明该成员函数不能对类的任何成员进行修改

编译器对const成员函数的处理如下:

一些const修饰变量或函数时的权限问题:

以上代码属于const修饰时的权限放大问题:把一个使用const修饰的变量作为实参传递给一个没有const修饰的形参,编译器报错

以上代码中,成员函数使用const修饰后, this指针指向的对象为const Date类型的,因此实参指向的对象可以是const Date类型的,也可以是Date类型的,因为权限平移和权限缩小都是允许的

总结:

  1. const对象不可以调用非const成员函数(权限放大不允许)
  2. 非const对象可以调用const成员函数(权限缩小允许)
  3. const成员函数内不可以调用其他的非const成员函数(权限放大不允许)
  4. 非const成员函数内可以调用其他的const成员函数(权限缩小允许)

凡是内部不改变成员变量,也就是*this对象数据的,这些成员函数都应该加const修饰

7. 取地址及const取地址操作符重载

这两个运算符一般不需要重载,使用编译器默认生成取地址的重载即可

//日期类
class Date
{
public:
	//取地址重载
	Date* operator&()
	{
		return this;
	}
	//const修饰的取地址操作符重载,给const对象调用
	const Date* operator&() const
	{
		return this;
	}
private:
	int _year;
	int _month;
	int _day;
};

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

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

相关文章

echarts 曲线图自定义提示框

<!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>曲线图</title><!-- 引入 ECharts 库 -->…

[word] word参考文献怎么对齐 #学习方法#微信#笔记

word参考文献怎么对齐 word参考文献怎么对齐&#xff1f; 未对齐的参考文献如下 全部选中参考文献内容 选中段落快捷窗口显示/隐藏编辑标记快捷方式和标号快捷方式中左对齐 选中之后参考文献又自动加了标号 把之前的角标和文字之间全部删除 完成图

黄金交易策略(Nerve Nnife.mql4):1秒救地球的第六单

一轮趋势做单&#xff0c;正常情况是5单便可以完成一轮盈利。但当开仓后快速追加5单也无法止盈的话&#xff0c;我们得找准极其苛刻的条件开出第6单&#xff0c;并指望完成利润覆盖。代码如下&#xff1a; if(count > 5 && count < 10 && isDown(small_…

JDK新特性

JDK新特性 函数式接口和Lambda 表达式Stream流操作新日期API操作其他新特性 Lambda 是一个匿名函数&#xff0c;我们可以把 Lambda表达式理解为是一段可以传递的代码&#xff08;将代码 像数据一样进行传递&#xff09;。可以写出更简洁、更 灵活的代码。作为一种更紧凑的代码…

STL - map 和 set

1、关联式容器 vector、list、deque、 forward_list(C11)等&#xff0c;这些容器统称为序列式容器&#xff0c;因为其底层为线性序列的数据结构&#xff0c;里面 存储的是元素本身 关联式容器也是用来存储数据的&#xff0c;与序列式容器不同的是&#xff0c;其里面存储的是<…

单片机与外设的交互

单片机与外设的交互是嵌入式系统中非常重要的一个基础知识点。单片机是一个集成在同一芯片上的中央处理器、存储器和输入/输出接口,它可以根据用户编写的程序与各种外部设备即外设进行交互。单片机与外设之间的交互主要通过单片机上的输入/输出口(I/O口)来实现。 I/O口的工作原…

HSM加密机原理:密钥管理和加密操作从软件层面转移到物理设备中 DUKPT 安全行业基础8

HSM加密机原理 硬件安全模块&#xff08;HSM&#xff09;是一种物理设备&#xff0c;设计用于安全地管理、处理和存储加密密钥和数字证书。HSM广泛应用于需要高安全性的场景&#xff0c;如金融服务、数据保护、企业安全以及政府和军事领域。HSM提供了一种比软件存储密钥更安全…

rsyslog远程记录系统日志

rsyslog是一个快速处理手机系统日志的开源程序&#xff0c;提供了高性能&#xff0c;安全功能和模块化设计&#xff0c;rsyslog是syslog的升级版&#xff0c;他讲多重来源输入输出转换结果到目的地&#xff0c;rsyslog被广泛用于Linux系统以通过TCP/UDP协议转发或接收日志消息。…

OpenCV每日函数 结构分析和形状描述符(9) ApproxPolyDP函数 拟合曲线

一、Douglas -Peucker 算法 也称为Ramer-Douglas-Peucker 算法或迭代端点拟合算法,是一种通过减少点数来平滑折线(由线性线段组成的线)的算法。简化曲线应保留原始曲线的粗略形状,但仅包含定义原始曲线的点的子集。 粗化程度由单个参数 ε 控制,该参数定义原始点和简化曲线…

【开源】JAVA+Vue.js实现森林火灾预警系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 系统基础模块2.3 烟雾传感器模块2.4 温度传感器模块2.5 历史记录模块2.6 园区数据模块 三、系统设计3.1 用例设计3.1.1 森林园区基础系统用例设计3.1.2 森林预警数据用例设计 3.2 数据库设计3.2.1 烟雾…

Oracle数据字典学习1

之前查看了几个用户的默认表空间&#xff0c;是从user_users来查看的&#xff1b; 根据资料&#xff1b; ORACLE中数据字典视图分为3大类,用前缀区别&#xff0c;分别为&#xff1a;USER&#xff0c;ALL 和 DBA&#xff1b; 许多数据字典视图包含相似的信息&#xff1b; USER_…

读书笔记之《运动改造大脑》:运动是最佳的健脑丸

《运动改造大脑》的作者是约翰•瑞迪&#xff08;John Ratey&#xff09; / 埃里克•哈格曼&#xff08;Eric Hagerman&#xff09;&#xff0c;原著名称为&#xff1a;Spark&#xff1a;the revolutionary new science of exercise and the brain&#xff0c;于 2013年出版约翰…

C语言第二十二弹---指针(六)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】 指针 1. 回调函数是什么&#xff1f; 2、qsort使用举例 2.1、使用qsort函数排序整型数据 2.2 使用qsort排序结构体数据 3、qsort函数的模拟实现 总结 1. 回…

【正在更新】从零开始认识语音识别:DNN-HMM混合系统语音识别(ASR)原理

摘要 | Abstract TO-BE-FILLED 1.前言 | Introduction 近期想深入了解语音识别(ASR)中隐马尔可夫模型(HMM)和深度神经网络-隐马尔可夫(DNN-HMM)混合模型&#xff0c;但是尽管网络上有许多关于DNN-HMM的介绍&#xff0c;如李宏毅教授的《深度学习人类语言处理》[1]&#xff0c;…

Minecraft的红石教程之电梯

一.前言 我记得是上初中的时候&#xff0c;就看到了这类电梯。现在我在看现在这类电梯的相关视频&#xff0c;大多是盗用创意未能领会其中的红石运作规律&#xff0c;于是我就删繁就简写了这篇。 二.步骤 1.材料 粘性活塞&#xff0c;黏液块&#xff0c;红石&#xff0c;红…

Mac电脑清空特别大型旧文件如何一键清理?

在我们的数字生活中&#xff0c;Mac电脑常常承载着大量个人资料和重要文件。但当我们决定把自己的Mac送给亲人或朋友使用时&#xff0c;面临的首要任务便是彻底且高效地清空所有个人数据&#xff0c;以保证隐私安全。传统的删除方法虽然简单&#xff0c;但往往不能彻底清除所有…

爬虫系列-web请求全过程剖析

&#x1f308;个人主页: 会编程的果子君 ​&#x1f4ab;个人格言:“成为自己未来的主人~” 上一小节我们实现了一个网页的整体抓取工作&#xff0c;那么本小节&#xff0c;给各位好好剖析一下web请求的全部过程&#xff0c;这样有助于后面我们遇到的各种各样的网站就有了入手…

H5 带网站测速引导页源码

H5 带网站测速引导页源码 源码介绍&#xff1a;一款带网站测速功能的引导页源码 下载地址&#xff1a; https://www.changyouzuhao.cn/10717.html

X图形

1.题目 这道题是蓝桥云课上面的一道题目&#xff0c;它是2022年蓝桥杯省模拟题&#xff0c;题目难度为简单。 考察的知识点为递归。 题目链接&#xff1a;X图形 2.思路 如何理解题意&#xff1f; 蓝桥杯的题目和Leetcode题目最大的不同点在于&#xff0c;蓝桥杯的题目大部…

【大厂AI课学习笔记】【1.6 人工智能基础知识】(2)机器学习

目录 必须理解的知识点&#xff1a; 举一个草莓的例子&#xff1a; 机器学习的三个类别&#xff1a; 监督学习&#xff1a; 无监督学习&#xff1a; 强化学习&#xff1a; 更多知识背景&#xff1a; 机器学习的诞生需求 监督学习的关键技术与实现步骤 无监督学习的关…