C++类与对象:默认成员函数

news2024/10/6 5:54:04

文章目录

  • 1.类的6个默认成员函数
  • 2.构造函数
  • 3.析构函数
  • 4. 拷贝构造函数
  • 5.赋值运算符和运算符重载
  • 6.日期类实现
  • 7.const成员
  • 8.重载流插入<< ,流提取>>
    • 1.流插入
    • 2.流提取
  • 9.取地址及const取地址操作符重载

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

空类:也就是什么成员都没有的类。

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

默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数。
在这里插入图片描述

2.构造函数

概念:

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

#include <iostream>
using namespace std;

class Date
{
public:
// 以下构造函数只能存在一个!!!
    // 无参默认构造函数
    Date()
    {
        _year = 1900;
        _month = 1;
        _day = 1;
    }
    // 全缺省默认构造函数
    Date(int year = 1900, int month = 1, int day = 1)
    {
        _year = year;
        _month = month;
        _day = day;
    }
    // 编译器生成的默认构造函数


    // C++11补丁新增内置类型成员变量(int char double 指针....)在类中声明时可以给默认值,此处仍是声明不是定义!!!
private:
    int _year = 0;
    int _month = 0;
    int _day = 0;
};
// 以下测试函数能通过编译吗?
void Test()
{
    Date d1;
}
int main()
{
    Test();
    return 0;
}

在这里插入图片描述

特性:

  • 函数名与类名相同,无返回值类型
  • 对象实例化时编译器自动调用对应的构造函数
  • 构造函数可以重载。
  • 构造函数的并不是开辟空间创建对象,而是初始化对象
  • 如果类中没有显式定义构造函数,则编译器会自动生成一个无参的默认构造函数,而用户显式定义编译器将不再生成
  • 不实现构造函数的情况下,编译器会生成默认的构造函数,此默认构造函数对内置类型不起作用,只对自定义类型初始化
  • C++11中针对内置类型成员不初始化的缺陷,又打了补丁:内置类型成员变量在类中声明时可以给默认值。

3.析构函数

概念:

析构函数:与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作是由编译器在栈区上完成的。而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作,一般清理的是堆上malloc开辟出来的空间

  • 函数名是在类名前加上字符 ~,无参数,无返回值类型
  • 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数,析构函数不能重载
  • 对象生命周期结束时,C++编译系统系统自动调用析构函数
  • 如果类中没有申请资源时,析构函数可以不写,直接使用编译器生成的默认析构函数,有资源申请时,一定要写,否则会造成资源泄漏,比如Stack类需要动态开辟空间
#include <iostream>
using namespace std;

class stack
{
public:

	void Push(const int& data)
	{
		// CheckCapacity();
		_array[_size] = data;
		_size++;
	}

	// 半缺省构造函数
	stack(int capacity = 10)
	{
		cout << "构造" << endl;
		_array = (int*)malloc(10 * sizeof(int));
		if (_array == nullptr)
		{
			perror("malloc fail");
			exit(-1);
		}
		_size = 0;
		_capacity = capacity;
	}

	// 析构函数
	~stack()
	{
		cout << "析构" << endl;
		free(_array);
		_array = NULL;
		_size = 0;
		_capacity = 0;
	}

	// 拷贝构造函数:深拷贝
	stack(const stack& st)
	{
		cout << "拷贝构造" << endl;

		_array = (int*)malloc(st._capacity * sizeof(int));
		if (_array == nullptr)
		{
			perror("malloc fail");
			exit(-1);
		}
		_size = st._size;
		_capacity = st._capacity;
	}
private:
	int* _array;
	int _size;
	int _capacity;

};

int main()
{
	stack st1;
	stack st2(st1);
	return 0;
}

在这里插入图片描述

4. 拷贝构造函数

概念:

拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰,防止原本对象被修改),在创建对象时,可以创建一个与已存在对象一某一样的新对象

特性:

  • 函数名是类名,无返回值类型,参数只有一个且必须是类对象的引用,使用传值方式编译器会报错,因为会引发无穷递归调用

  • 拷贝构造函数是构造函数的一个重载形式

  • 若未显式定义拷贝构造函数,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数根据对象按内存大小存储,按字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝

  • 类中如果没有涉及资源申请时,拷贝构造函数写不写都可以,一旦涉及到资源申请时,则拷贝构造函数一定要写成深拷贝的,否则默认拷贝构造函数为浅拷贝

// 拷贝构造:浅拷贝
#include <iostream>
using namespace std;

class Date
{
public:
    ~Date()
    {
        cout << "~Data()" << endl;
    }
    Date(int year = 2024, int month = 1, int day = 1)
    {
        _year = year;
        _month = month;
        _day = day;
        cout << "Data()" << endl;
    }
    /*
    拷贝构造函数:浅拷贝
    Date(const Date& d)
    {
        _year = d._year;
        _month = d._month;
        _day = d._day;
        cout << "Data(Date& d)" << endl;
    }
    */
private:
    int _year = 0;
    int _month = 0;
    int _day = 0;
};

int main()
{
    // c++规定自定义类型都会调用拷贝构造,传引用传参就不会调用拷贝构造了,否则会无限递归
    Date d1(2024,1,28);
    Date d2(d1);
    return 0;
}

在这里插入图片描述

#include <iostream>
using namespace std;

class stack
{
public:
    
	void Push(const int& data)
	{
		// CheckCapacity();
		_array[_size] = data;
		_size++;
	}
	// 半缺省构造函数
	stack(int capacity = 10)
	{
		_array = (int*)malloc(10 * sizeof(int));
		if (_array == nullptr)
		{
			perror("malloc fail");
			exit(-1);
		}
		_size = 0;
		_capacity = capacity;
		cout << "构造" << endl;
	}

	// 析构函数
	~stack()
	{
		free(_array);
		_array = NULL;
		_size = 0;
		_capacity = 0;
	}

	// 拷贝构造函数:深拷贝
	stack(const stack& st)
	{
		_array = (int*)malloc(st._capacity * sizeof(int));
		if (_array == nullptr)
		{
			perror("malloc fail");
			exit(-1);
		}
		_size = st._size;
		_capacity = st._capacity;
	}

private:
	int* _array;
	int _size;
	int _capacity;

};

int main()
{
	stack st1;
	stack st2(st1);
	return 0;
}

在这里插入图片描述

5.赋值运算符和运算符重载

运算符重载

C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似

  • 重载操作符必须有一个类类型参数
  • 用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不能改变其含义
  • 作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this指针
  • .* :: sizeof ?: . 注意以上5个运算符不能重载

赋值运算符重载

  • 参数类型:const T&,传递引用可以提高传参效率
  • 返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值
  • 检测是否自己给自己赋值
  • 返回*this :符合连续赋值的含义

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

  • 赋值运算符的左操作数是被赋值的对象本身,而右操作数是要赋给该对象的值。因此,赋值运算符的操作涉及到两个对象:被赋值对象和赋值对象。如果定义为全局函数,就需要两个参数,而如果定义为成员函数,就只需要一个参数,因为左操作数可以通过this指针访问。
  • 如果定义为全局函数,就可能出现二义性,因为编译器会为每个类隐式地定义一个赋值运算符。如果再定义一个全局的赋值运算符,就会导致编译器无法确定调用哪个函数。
  • 如果定义为全局函数,就可能破坏类的封装性,因为全局函数无法访问类的私有成员或静态成员。如果要访问这些成员,就需要将全局函数声明为类的友元函数,这样就会增加类的复杂性和耦合性。
  • 如果定义为全局函数,就可能导致语义不清,因为赋值运算符通常是类的内在行为,与类的具体实现密切相关。如果将赋值运算符定义为全局函数,就会使得类的实现细节暴露给外部,降低了类的抽象性和可维护性。

为什么运算符重载可以重载成全局函数呢?

  • 全局函数可以支持左操作数不是类对象的情况,例如可以将数字和向量对象相乘,而不仅仅是向量对象和数字相乘。
  • 全局函数可以避免重载运算符时的二义性,例如如果重载赋值运算符为全局函数,就不会与编译器隐式定义的赋值运算符冲突。
  • 全局函数可以提高运算符的灵活性和通用性,例如可以重载输入/输出运算符,使得可以用 cout 和 cin 来输出和输入类对象。
  • 全局函数可以保持运算符的对称性,例如如果重载加法运算符为全局函数,就可以同时支持 a+b 和 b+a 的形式,而不需要为每种情况都定义一个成员函数。

6.日期类实现

Date.h:

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

// 日期类实现
class Date
{
public:
	Date(int year = 2024, int month = 1, int day = 1);
	~Date();
	Date(const Date& d);	// 同类型对象进行初始化

	// 获取某年某月的天数
	int GetMonthDay(int year, int month) const	// 直接在类中定义相当于inline内联展开(此函数我们后续需要频繁调用)
	{
		assert(month > 0 && month < 13);
		static int monthday[] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };// 数组放到静态区,增加程序效率
		// 1.四年一润百年不润 2.四百年一润
		if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0))
		{
			return 29;
		}
		return monthday[month];
	}
	/*
		将const修饰的“成员函数”称之为const成员函数,const修饰类成员函数,
		实际修饰该成员函数隐含的this指针指向的内容,表明在该成员函数中不能对类的任何成员进行修改
	*/
	void Print() const
	{
		cout << _year << '-' << _month << '-' << _day << endl;
	}

	/*
	1.	运算符重载成全局的就需要成员变量是公有的,问题来了,封装性如何保证?友元解决或者干脆重载成类的成员函数
	2.	赋值运算符只能重载成类的成员函数不能重载成全局函数
	*/
	bool operator==(const Date& d) const;
	bool operator>(const Date& d) const;
	bool operator >= (const Date& d) const;
	bool operator < (const Date& d) const;
	bool operator <= (const Date& d) const;
	bool operator != (const Date& d) const;

	Date operator=(const Date& d);
	Date operator+(int day) const;
	Date& operator+=(int day);
	Date operator-(int day) const;
	Date& operator-=(int day);

	// 前置++运算符重载
	Date& operator++();
	// 后置++运算符重载
	Date operator++(int);
	// 前置--运算符重载
	Date& operator--();
	// 后置--运算符重载
	Date operator--(int);

	// 流插入 << 重载:返回值目的为了支持连续性
	friend ostream& operator<<(ostream& out, const Date& d);
	// 流提取 >> 重载:返回值目的为了支持连续性
	friend istream& operator>>(istream& in, Date& d);


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

Date.cpp:

#include"Date.h"
// 声明和定义分离

// 构造函数
Date::Date(int year, int month, int day)
{
	this->_year = year;
	this->_month = month;
	this->_day = day;
}

// 深度拷贝构造函数
Date::Date(const Date& d)
{
	this->_year = d._year;
	this->_month = d._month;
	this->_day = d._day;
}

// 析构函数
Date::~Date()
{
	this->_year = 2024;
	this->_month = 1;
	this->_day = 1;
}

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

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

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

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

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

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

Date Date::operator=(const Date& d)
{
	if (this != &d)
	{
		this->_year = d._year;
		this->_month = d._month;
		this->_day = d._day;
	}
	return *this;
}

Date Date::operator+(int day) const
{
	Date tmp = *this;// 赋值重载拷贝防止原来的日期被改变
	tmp._day = tmp._day + day;
	int monthday = Date::GetMonthDay(tmp._year, tmp._month);
	if (tmp._day <= monthday)
	{
		return tmp;
	}
	while (tmp._day > monthday)
	{
		monthday = Date::GetMonthDay(tmp._year, tmp._month);
		tmp._day = tmp._day - monthday;
		if (tmp._month < 12)
		{
			tmp._month++;
		}
		else
		{
			tmp._month = 1;
			tmp._year++;
		}
	}
	return tmp;
}

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

Date Date::operator-(int day) const
{
	Date tmp = *this;// 赋值重载拷贝防止原来的日期被改变
	tmp._day = tmp._day - day;
	int monthday = Date::GetMonthDay(tmp._year, tmp._month);
	if (tmp._day > 0)
	{
		return tmp;
	}
	while (tmp._day <= 0)
	{
		if (tmp._month == 1)
		{
			tmp._month = 12;
			tmp._year--;
		}
		else
		{
			tmp._month--;
		}
		monthday = Date::GetMonthDay(tmp._year, tmp._month);
		tmp._day = tmp._day + monthday;
	}
	return tmp;
}

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

// 前置++
Date& Date::operator++()
{
	this->_day++;
	int monthday = Date::GetMonthDay(this->_year, this->_month);
	if (this->_day > monthday)
	{
		this->_month++;
		this->_day = this->_day - monthday;
		if (this->_month > 12)
		{
			this->_month = 1;
			this->_year++;
		}
	}
	// 返回的是对象++后的全新的对象
	return *this;
}

// 后置++
Date Date::operator++(int)// 注意为何返回值区分了对象本身和对象的引用,在后置++中我们返回的是tmp这个局部变量因此只能返回局部对象的拷贝而不能返回引用
{
	Date tmp = *this;
	this->_day++;
	int monthday = Date::GetMonthDay(this->_year, this->_month);
	if (this->_day > monthday)
	{
		this->_month++;
		this->_day = this->_day - monthday;
		if (this->_month > 12)
		{
			this->_month = 1;
			this->_year++;
		}
	}
	//返回的是对象++之前的对象的拷贝
	return tmp;
}

// 前置--
Date& Date::operator--()
{
	this->_day--;
	if (this->_day > 0)
	{
		return *this;
	}
	else
	{
		this->_month--;
		if (this->_month == 0)
		{
			this->_month = 12;
			this->_year--;
		}
		int monthday = Date::GetMonthDay(this->_year, this->_month);
		this->_day = this->_day + monthday;
		return *this;
	}
}

// 后置--
Date Date::operator--(int)
{
	Date tmp = *this;
	this->_day--;
	if (this->_day > 0)
	{
		return tmp;
	}
	else
	{
		this->_month--;
		if (this->_month == 0)
		{
			this->_month = 12;
			this->_year--;
		}
		int monthday = Date::GetMonthDay(this->_year, this->_month);
		this->_day = this->_day + monthday;
		return tmp;
	}
}

// 友元函数
//
// 流插入 << 重载
ostream& operator<<(ostream& out, const Date& d)
{
	cout << d._year << "年" << d._month << "月" << d._day << "日" << endl;
	return out;
}
// 流提取 >> 重载
istream& operator>>(istream& in, Date& d)
{
	cout << "请依次输入年月日:" << endl;
	in >> d._year >> d._month >> d._day;
}

7.const成员

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

读函数:建议加const

写函数:谨慎加const

// 读函数
void Print() const
{
	cout << _year << '-' << _month << '-' << _day << endl;
}

// 写函数
// 构造函数
Date::Date(int year, int month, int day) const //错误const加入
{
	this->_year = year;
	this->_month = month;
	this->_day = day;
}
  1. [const对象不能调用非const成员函数,因为这样会破坏const对象的不可变性,或者导致类型不匹配的错误。如果非要调用非const成员函数,就需要使用const_cast来强制去除const限定]。
  2. [非const对象可以调用const成员函数,因为这样不会改变非const对象的状态,或者导致类型不匹配的错误。非const对象可以隐式转换为const对象,从而调用const成员函数]。
  3. [const成员函数不能调用其它的非const成员函数,因为这样会破坏const成员函数的不可变性,或者导致类型不匹配的错误。如果非要调用非const成员函数,就需要对this指针使用const_cast来强制去除const限定]。
  4. [非const成员函数可以调用其它的const成员函数,因为这样不会改变非const成员函数的状态,或者导致类型不匹配的错误。非const成员函数可以隐式转换为const成员函数,从而调用const成员函数]。

总之,const的调用满足权限可以缩小但不可以放大,也就是说非const修饰的对象或函数可以调用const修饰的对象或函数,但const修饰的对象或函数不可以调用非const修饰的对象或函数。

8.重载流插入<< ,流提取>>

1.流插入

这样写ok么?

// 日期类实现
class Date
{
public:
	Date(int year = 2024, int month = 1, int day = 1)
    {
        _year = year;
        _month = month;
        _day = day;
    }
    //流插入<<重载成为成员函数
    void operator<<(ostream& out)
	{
	cout << this->_year << "年" << this->_month << "月" << this->_day << "日" << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1(2024,2,1);
    //错误运行;
    cout<<d1;//cout作为左操作数,d1作为右操作数,d1日期类对象插入到控制台cout中去符合思维,但实际报错
    
    //正确运行:
	d1<<cout;//d1作为左操作数,cout作为右操作数,重载成功但是发现逻辑是控制台cout插入到日期类d1中
	return 0;
}

本质原因是什么呢?

解释:

<< 作为成员函数重载,this指针占据了第一个参数,意味着日期类(Date)对象必须是左操作数,因此我们要设法让cout作为第一个参数,因此为了实现这个操作符重载,我们不能将它写为成员函数,应当写为全局函数但是当我们将函数写成全局函数后面临它无法访问私有,因此此处我们要么私有公开为公有,要么使用友元,并且注意全局函数不能在.h头文件中定义,否则链接时候会发生重定义

在这里插入图片描述

第一种方式:

// 流输出 << 重载为全局函数,并且将类对象成员私有公开
void operator<<(ostream& out,const Date& d)
{
	cout << d._year << "年" << d._month << "月" << d._day << "日" << endl;
}

在这里插入图片描述

第二种方式:

设置Get,Set函数获取私有成员的值(不想破坏封装,可以替换掉友元)

第三种方式:

友元函数

friend void operator<<(ostream& out, const Date& d);

在这里插入图片描述

问题来了:我们实现的流插入如何支持连续插入呢?cout<<......<<......<<.......<<endl;

与赋值类似,不过结合性顺序相反:

cout<<d1<<d2<<;cout<<d1为一次函数调用,并且带有一个返回值作为左操作数再次进行流插入。

流插入:

friend ostream& operator<<(ostream& out, const Date& d);

ostream& operator<<(ostream& out, const Date& d)
{
	cout << d._year << "年" << d._month << "月" << d._day << "日" << endl;
	return out;
}

为什么C++要支持流插入和自定义重载流插入呢?因为C语言中的printf函数无法支持自定义类型直接通过printf输出,而流插入就很好的解决了所有对象的打印问题,无论是内置类型还是自定义类型。

2.流提取

流提取:

friend istream& operator>>(istream& in, Date& d);
istream& operator>>(istream& in, Date& d)
{
	cout << "请依次输入年月日:" << endl;
	in >> d._year >> d._month >> d._day;
}

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

这两个运算符一般不需要重载,直接取得对象的地址即可,使用编译器生成的默认取地址的重载即可,只有特殊情况,才需要重载,一般不需要自己重写

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

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

相关文章

Spring Boot集成Redisson详细介绍

Redisson是一个用于Java的分布式和高可用的Java对象的框架&#xff0c;它基于Redis实现。在Spring Boot应用程序中集成Redisson可以帮助我们更轻松地实现分布式锁、分布式对象、分布式集合等功能。本文将介绍如何在Spring Boot项目中集成Redisson&#xff0c;并展示一些基本用法…

vs正则搜索 int main() 排除 // int main()

1 ctrl f 2 选择正则 3 表达式 ^\s*int\smain\(\) ^ 表示匹配行开始\s* 匹配0个或多个空格int 匹配int关键字\s 匹配一个或多个空格main\( 匹配main函数和左括号

ChatGPT真有很多人在用吗?——回答一位知友的问题

先上结论 是的。数据不会撒谎&#xff0c;用户拿脚投票&#xff0c;ChatGPT发布仅五天内就达到了100万用户&#xff0c;是有史以来增长最快的消费者应用程序。2023年全球前50款AI工具就收获了240亿次访问&#xff0c;其中ChatGPT收获了146亿次访问。 一些想法和思考 我的一些…

9.defer语句调用顺序

目录 概述实践defer结果defer和return执行顺序 结束 概述 defer 类似 java 中的异常处理中的 finally &#xff0c;在 Go 中 defer 是一种压栈出栈操作。 实践 defer package mainimport "fmt"func demo1() {fmt.Println("demo1") }func demo2() {fmt.Pr…

MySql调优(三)Query SQL优化(2)profiler诊断工具

Mysql中自带性能分析工具Profile。注意&#xff1a;profile仅对当前会话有效 一、操作步骤 1、打开 profile set profiling1; 2、执行sql语句 3、分析sql语句执行时间 show profiles 其他参数&#xff1a; ALL&#xff1a;显示所有的开销信息。 BLOCK IO&#xff1a;显示块…

深入理解 Golang 的 crypto/elliptic:椭圆曲线密码学的实践指南

深入理解 Golang 的 crypto/elliptic&#xff1a;椭圆曲线密码学的实践指南 引言crypto/elliptic 库概览基本使用教程高级应用案例性能与安全考量结论 引言 在当今数字时代&#xff0c;数据安全和加密技术成为了信息技术领域的重中之重。特别是在网络通信和数据存储领域&#…

使用Java实现HTTP持久连接:一次与网络的“长聊“

大家都知道&#xff0c;传统的HTTP连接就像是一次性的餐具&#xff0c;每发送一个请求&#xff0c;就得重新建立一个连接&#xff0c;然后快速用完就扔。这对于网络资源来说&#xff0c;简直就是一场"大肆挥霍"的派对。但幸好&#xff0c;我们有HTTP持久连接&#xf…

大力说视频号第三课:手把手教你视频号如何认证

视频号生态不断完善&#xff0c;越来越多的创作者认识到视频号认证的重要性。微信视频号认证不但能提升搜索排名&#xff0c;还能直播推流、与企业微信的关联等优势。 今天大力就来向大家介绍一下视频号如何做认证。 01 个人认证 个人认证又包括兴趣认证和职业认证。 A、兴趣…

华为突然官宣:新版鸿蒙系统,正式发布

华为&#xff0c;一家始终引领科技创新潮流的全球性企业&#xff0c;近日再次引发行业震动——全新HarmonyOS NEXT&#xff0c;被誉为“纯血版鸿蒙”的操作系统正式官宣。这是华为在操作系统领域迈出的坚实且具有突破性的一步&#xff0c;标志着华为正逐步摆脱对安卓生态系统的…

Ajax 详解及其使用

Ajax&#xff08;Asynchronous JavaScript and XML&#xff09;是一种在客户端与服务器之间进行异步通信的技术&#xff0c;它允许网页在不重新加载整个页面的情况下&#xff0c;与服务器交换数据并更新部分网页内容。Ajax 的核心是XMLHttpRequest&#xff08;XHR&#xff09;对…

【异常处理】word或ppt打开后没反应或闪退,或者报错由安全模式打开

折腾了2个小时&#xff0c;可算解决了&#xff0c;办法是在【控制面板】中右击&#xff0c;选择【更改】 选择联机修复&#xff0c;然后耐心等待&#xff0c;最后再打开就没问题了。

Task05:PPO算法

本篇博客是本人参加Datawhale组队学习第五次任务的笔记 【教程地址】https://github.com/datawhalechina/joyrl-book 【强化学习库JoyRL】https://github.com/datawhalechina/joyrl/tree/main 【JoyRL开发周报】 https://datawhale.feishu.cn/docx/OM8fdsNl0o5omoxB5nXcyzsInGe…

消息队列的应用场景

消息队列的应用场景 消息队列中间件是分布式系统中重要的组件&#xff0c;主要解决应用耦合&#xff0c;异步消息&#xff0c;流量削锋等问题实现高性能&#xff0c;高可用&#xff0c;可伸缩和最终一致性架构使用较多的消息队列有ActiveMQ&#xff0c;RabbitMQ&#xff0c;Ze…

vue 发布自己的npm组件

1、在项目任意位置创建index.ts文件 2、导入要到处的组件&#xff0c;使用vue提供的install 功能全局挂在&#xff1b; import GWButton from "/views/GWButton.vue"; import GWAbout from "/views/AboutView.vue";const components {GWButton,GWAbout, …

YOLOv8改进:下采样系列 | 一种新颖的基于 Haar 小波的下采样HWD,有效涨点系列

💡💡💡本文独家改进:HWD的核心思想是应用Haar小波变换来降低特征图的空间分辨率,同时保留尽可能多的信息,与传统的下采样方法相比,有效降低信息不确定性。 💡💡💡使用方法:代替原始网络的conv,下采样过程中尽可能包括更多信息,从而提升检测精度。 收录 YO…

总结了一下中继引擎(can中继器,TCP总机器)开发实际经验

多路数据进行中继的研究 1.数据中继的概念 数据中继是一种数据传输技术&#xff0c;用于在两个通信设备之间提供数字信号的传输。它利用数字信道传输数据信号&#xff0c;可以提供永久性和半永久性连接的数字数据传输信道。 数据中继的主要作用是提高通信质量和可靠性&#xf…

OpenCV 13 - 图像对比度和亮度的调节基本阈值操作

1 图像阈值 图像阈值是一种图像处理技术,用于将图像转换为二值图像。通过设定一个阈值,将图像中的像素值与阈值进行比较,将大于或小于阈值的像素分别设置为不同的像素值,从而实现图像的二值化处理。 2 阈值类型 2-1 阈值类型-阈值二值化(threshold binary) 2-2 阈值类型…

three.js CSS2DRenderer、CSS2DObject渲染HTML标签

有空的老铁关注一下我的抖音&#xff1a; 效果&#xff1a; <template><div><el-container><el-main><div class"box-card-left"><div id"threejs" style"border: 1px solid red;position: relative;"><…

浅谈安科瑞直流表在沙特基站的应用

摘要&#xff1a;本文介绍了安科瑞直流电表在沙特基站的应用。主要用于沙特某基站的电流电压电能的计量&#xff0c;配合分流器对基站进行计量。 Abstract: This article introduces the application of Acrel DC meters in base station in Saudi Arabia.The device is meas…

iMazing 3中文版双平台版本同步,iOS 设备在 Windows 上也能自动备份了

自从WWDC 2019 宣布 iTunes 退役后&#xff0c;也许很多小伙伴都对「上位者」iMazing 有所耳闻。 这款设计更加人性化、功能细致强大的 iOS 备份管理工具。 iMazing 支持在 Windows 及 Mac 上运行&#xff0c;而这个月 Windows 版本更新至 2.17. 之后&#xff0c;iMazing 的双…