C++拷贝构造函数和运算符重载

news2025/3/9 10:24:45

目录

一,拷贝构造函数

二,运算符重载


一,拷贝构造函数

概念:在类的定义中,构造函数只是单纯将内置类型进行初始化,而拷贝构造函数是将整个类进行拷贝到另一个类中进行初始化。在定义拷贝构造函数时,只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用。

这里要说明的是,拷贝构造函数也是特殊的成员函数,其特征如下:

        1,拷贝构造函数是构造函数的一个重载形式。

        2,拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错,因为形参相当于实参的临时拷贝,在拷贝中会触发另一个拷贝构造函数的调用,从而引发无穷递归调用。传引用的话只会将源对象的别名进行拷贝,不会进行整体拷贝,从而避免了这种问题。

class Date
{
public:
    Date(int year = 1900, int month = 1, int day = 1)
    {
        _year = year;
        _month = month;
        _day = day;
    }
    //Date(const Date d)// 错误写法: 编译报错,会引发无穷递归
    Date(const Date& d)// 正确写法
    {
        _year = d._year;
        _month = d._month;
        _day = d._day;
    }
private:
    int _year;
    int _month;
    int _day;
};
int main()
{
    Date d1;//调用构造函数
    Date d2(d1);//用类进行初始化,会调用拷贝构造函数
    return 0;
}

引发无穷递归的过程图

        3,若未显式定义,编译器会生成默认的拷贝构造函数。默认的拷贝构造函数只会进行浅拷贝,或者值拷贝。(浅拷贝是指只拷贝对象的基本数据类型和引用地址,不会拷贝引用地址所指向的对象,即原对象中的数据所指向的空间将与拷贝后的对象的数据所指向的空间相同)。

        这里要说明的是默认拷贝构造函数的处理对象不跟默认构造函数一样,但处理自定义类型的方式跟默认构造函数一样。默认拷贝构造函数会对自定义类型和内置类型都做处理,其中,内置类型成员完成浅拷贝,自定义类型成员将会调用这个成员的拷贝构造

#include <iostream>
using namespace std;
class Time
{
public:
    Time() {
        _hour = 1;
        _minute = 1;
        _second = 1;
    }
    Time(const Time& t) {
        _hour = t._hour;
        _minute = t._minute;
        _second = t._second;
        cout << "Time对象的拷贝构造" << endl;
    }
private:
    int _hour;
    int _minute;
    int _second;
};
class Date
{
private:
    // 内置类型
    int _year = 1970;
    int _month = 1;
    int _day = 1;
    // 自定义类型,将会调用此对象的拷贝构造
    Time _t;
};
int main()
{
    Date d1;
    Date d2(d1);
    return 0;
}

d1类运行的调试内部分析图(构造函数)

d2类运行的调试内部分析图(拷贝构造函数)

        下面问题来了,既然有默认拷贝构造函数,我们需要不需要再定义拷贝构造函数呢?

        请注意上面说的,默认拷贝构造只会进行浅拷贝,当我们在对象成员中开辟了动态空间时,使用默认拷贝构造将会出现问题。请看以下代码:

//此代码运行时将会崩溃
#include <iostream>
using namespace std;
typedef int DataType;
class Stack
{
public:
	Stack(size_t capacity = 10)
	{
		_array = (DataType*)malloc(capacity * sizeof(DataType));
		if (!_array) {
			perror("malloc申请空间失败");
			return;
		}
		_size = 0;
		_capacity = capacity;
	}
	~Stack()
	{
		if (_array) {
			free(_array);
			_array = nullptr;
			_capacity = 0;
			_size = 0;
		}
	}
private:
	DataType* _array;
	size_t _size;
	size_t _capacity;
};
int main()
{
	Stack s1;
	Stack s2(s1);
	return 0;
}

分析: 

        首先,s1先调用构造函数创建,在构造函数中开辟了10个元素的空间,然后,s2对象使用s1拷贝构造,Stack对象中没有自己定义,系统将生成一份默认的拷贝构造函数进行浅拷贝,这时,s1和s2栈结构将同时指向一块内存空间,当函数退出时,s2和s1会自动调用析构函数进行销毁,这就会造成s1和s2指向的同一块空间销毁两次,系统崩毁。

        解决上面的问题不难,我们只需将s1和s2分别指向不同的空间即可,这时,需要我们自己定义拷贝构造函数。

#include <iostream>
using namespace std;
typedef int DataType;
class Stack
{
public:
	Stack(size_t capacity = 10)
	{
		_array = (DataType*)malloc(capacity * sizeof(DataType));
		if (!_array) {
			perror("malloc申请空间失败");
			return;
		}
		_size = 0;
		_capacity = capacity;
	}
	//定义拷贝构造
	Stack(const Stack& S)
	{
		_size = S._size;
		_capacity = S._capacity;
		_array = (DataType*)malloc(_capacity * sizeof(DataType));
		if (!_array) {
			perror("malloc申请空间失败");
			return;
		}
	}
	~Stack()
	{
		if (_array) {
			free(_array);
			_array = nullptr;
			_capacity = 0;
			_size = 0;
		}
	}
private:
	DataType* _array;
	size_t _size;
	size_t _capacity;
};
int main()
{
	Stack s1;
	Stack s2(s1);
	return 0;
}

总:如果类中没有涉及空间资源的申请时,拷贝构造函数可以不写,但是一旦涉及到资源空间的申请时,则拷贝构造函数是一定要写上的。

拷贝构造函数典型调用场景:

        1,使用已存在对象创建新对象。如同以上Stack类中s2的创建。

/*..........*/

int main()
{
    Stack s1;
    Stack s2(s1);//使用已存在的对象s1来创建对象s2
    return 0;
}

        2,函数参数类型为类类型对象——解析:因为在传参过程中,形参就相当于实参的临时拷贝,相当于用实参来创建形参。

        3,函数返回值类型为类类型对象——解析:当函数返回时,函数内局部对象的生命周期结束,但是临时变量的值会被拷贝到调用函数的栈帧中,或者通过引用传递给调用函数。当返回类类型对象时,直接将此类对象拷贝到调用函数栈帧中。

总结一句话,只要是运用了类对象与类对象直接赋值进行初始化的情况,系统就会调用拷贝构造。而为了提高效率,一般能用引用就用引用。


二,运算符重载

引入:

        在内置类型中,系统给我们自动定义了很大运算符,如:+、-、*、/、++、--、>等。这些内置类型和内置类型运算符的使用都是系统定义好的,可直接使用。现在问题来了,自定义类型要想使用这些运算符又当如何?由于自定义类型是我们自己定义的,系统不知道其结构,所以无法直接供我们使用,但C++为了增强代码的可读性引入了运算符重载的概念,可让自定义类型也使用这些运算符。运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。

运算符重载的定义:

        函数名:关键字operator后面接需要重载的运算符符号。

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

这里有以下5个注意:

        1,不能通过连接其他符号来创建新的操作符:比如operator@

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

        3,用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不能改变其+本身的含义

        4,作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this指针。

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

在类的内部定义

第一个参数为this指针

// '='操作符,返回类型为类类型Date的引用
Date& operator=(const Date& d);

Date& Date::operator=(const Date& d);//此种情况是在类中声明,在外部实现,用限定符说明是类对象中的成员函数
// "+="操作符,返回类型为类类型Date的引用
Date& operator+=(int day);

Date& Date::operator+=(int day);//此种情况是在类中声明,在外部实现,用限定符说明是类对象中的成员函数
// '+'操作符,返回类型为类类型Date的引用
Date operator+(int day);

Date Date::operator+(int day);//此种情况是在类中声明,在外部实现,用限定符说明是类对象中的成员函数
// '-'操作符,返回类型为类类型Date的引用
Date operator-(int day);

Date Date::operator-(int day);//此种情况是在类中声明,在外部实现,用限定符说明是类对象中的成员函数
// "-="操作符,返回类型为类类型Date的引用
Date& operator-=(int day);

Date& Date::operator-=(int day);//此种情况是在类中声明,在外部实现,用限定符说明是类对象中的成员函数

在类的外部定义

没有默认参数,需要把类写入形参中

// "+="操作符,返回类型为类类型Date的引用
Date& operator+=(const Date& d1, int day);
// '+'操作符,返回类型为类类型Date的引用
Date operator+(const Date& d1, int day);
// '-'操作符,返回类型为类类型Date的引用
Date operator-(const Date& d1, int day);
// "-="操作符,返回类型为类类型Date的引用
Date& operator-=(const Date& d1, int day);

运用细节演示:

        (1)首先,我们先对“ >,<,>=,<=,==,!= ”这几个简单运算符在类对象内定义进行演示和解说。

#include <iostream>
#include <assert.h>
using namespace std;
//再次提醒一下,类对象中的成员函数第一个默认参数为this,且指向此对象,下面运用时就不做说明
class Date
{
public:
	// 全缺省的构造函数
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	// ==运算符重载
	bool operator==(const Date& d)
	{
		return _year == d._year &&
			_month == d._month &&
			_day == d._day;
	}
	// !=运算符重载
	bool operator != (const Date& d)
	{
		return !(*this == d);
	}
	// >运算符重载
	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;
	}
	// <运算符重载
	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;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1;
	Date d2(2023, 10, 16);
	cout << (d1 > d2) << endl;//d1 > d2等效于d1.operator>(d2),这两个表达的意思一样
	cout << d1.operator>(d2) << endl;
	return 0;
}

        在上面代码中要说明的是在运算符表示过程中,我们即可用函数来表示运算符的含义,也可直使用运算符的形式表示含义。

在上面的运算符函数中:

d1 > d2等效于d1.operator(d2)

d1 == d2等效于d1.operator(d2)

上面的输出流中之所以(d1 > d2)用括号括起来是因为“ << ”操作符的运算级别高,会先与之运算。

        (2)接下来我们对“ +,-,+=,-= ”这几个简单运算符在类对象内定义进行演示和解说。

#include <iostream>
#include <assert.h>
using namespace std;
class Date
{
public:
	// 获取某年某月的天数
	int GetMonthDay(int year, int month)
	{
		assert(year >= 1 && (month >= 1 && month <= 12));
		int MonthDays[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
		if ((month == 2) && ((year % 400 == 0) || (year % 4 == 0 && year % 100 != 0)))
			return 29;
		return MonthDays[month];
	}
	// 全缺省的构造函数
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	// 日期-天数
	Date operator-(int day)
	{
		_day -= day;
		while (_day < 0) {
			if (_month == 1) {
				_year--;
				if (_year < 0) {
					perror("Date Count Error:");
					exit(-1);
				}
				_month = 12;
			}
			else {
				_month--;
			}
			_day += GetMonthDay(this->_year, this->_month);
		}
		return *this;
	}
	// 日期-=天数
	Date& operator-=(int day)
	{
		Date DateCopy(*this);
		//用临时对象返回,相当于函数的返回,需要有个对象去接收,而改变的只是临时对象
		//像直接使用类d1 -= 5,表达的只是此函数的功能,d1的值不会改变,若是d1 = d1 -= 5将会改变
		//DateCopy = DateCopy.operator-(day);
		//return DateCopy;

		//this指针直接指向的是此对象(即此类),用this指针来改变相当于直接改变了d1,类似于达到了改变d1的效果
		*this = DateCopy.operator-(day);
		return *this;
	}
	// 日期+=天数
	Date& operator+=(int day)
	{
		_day += day;
		while (_day > GetMonthDay(this->_year, this->_month)) {
			_day -= GetMonthDay(this->_year, this->_month);
			_month++;
			if (_month > 12) {
				_year++;
				_month -= 12;
			}
		}
		return *this;
	}
	// 日期+天数
	Date operator+(int day)
	{
		Date DateCopy(*this);
		DateCopy.operator+=(day);
		return DateCopy;
	}
	// 日期-日期 返回天数
	int operator-(const Date& d)
	{
		int YearDay = 0, MonthDay = 0, Day = _day - d._day;
		while (--_month) {
			MonthDay += GetMonthDay(_year, _month);
		}
		int month = d._month;
		while (--month) {
			MonthDay -= GetMonthDay(d._year, month);
		}
		_year--;
		int year = d._year - 1;
		for (int YearCount = _year - year; YearCount > 0; YearCount--) {
			YearDay += 365;
			if ((_year % 400 == 0) || ((_year % 4 == 0) && (_year % 100 != 0)))
				YearDay += 1;
			_year--;
		}
		return YearDay + MonthDay + Day;
	}
	void Print() {
		cout << _year << "/" << _month << "/" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1(2023, 10, 16);
	Date d2;
	//+=和+运算符重载
	//这里要说明的是,由于"+="没有返回值,所以在函数对象内部改变的时候一定要用this指针来改变,this指针指向d1
	d1 += 365;
	cout << "d1重载d1+=365: ";
	d1.Print();
	d2 = d1 + 23;
	cout << "d2重载d2=d1+23: ";
	d2.Print();
	//-=和-的运算符重载
	//"-="运算符与"+="同理
	d1 -= 365;
	cout << "d1重载d1-=365: ";
	d1.Print();
	d2 = d1 - 365;
	cout << "d2重载d2=d1-365: ";
	d2.Print();
	//日期-日期的运用
	cout << "d2-d1: " << d2 - d1 << endl;
	return 0;
}

        这里要注意的是函数的返回类型,“ +=,-= ”运算一般是不需要返回类型的,所以在内部实现要用this访问,从而间接实现原对象的运算。“ +,- ”操作符要有返回类型去接收,可直接返回临时对象。

        (3)“ 前置++,后置++,前置--,后置-- ”在类对象内定义进行演示和解说。

    // 后置++,形参为int,C++专门规定,为了与前置++区分
    Date operator++(int) {
        Date ret(*this);
        *this += 1;
        return ret;
    }
    // 前置++
    Date& operator++() {
        *this += 1;
        return *this;
    }
    // 后置--,形参为int,C++专门规定,为了与前置--区分
    Date operator--(int) {
      //先将原本类进行拷贝,然后将此对象里的值--,返回此对象,实现了先赋值,再--
        Date ret(*this);
        *this -= 1;
        return ret;
    }
    // 前置--
    Date& operator--() {
      //直接返回*this,实现了先把对象的值--,然后将此对象返回,实现了先--,再赋值
        *this -= 1;
        return *this;
    }

        这里要注意的是前置++、前置--和后置++、后置--的写法和前置和后置的实现。如上代码中C++的专门规定前置与后置的写法,前置的实现是先进行运算,然后再进行赋值,所以要直接用this进行。后置的实现要先进行赋值,然后再运算。这里我们虽然实现了this的运算,但返回的是运算前的对象,进而实现了此原理。

        (4)赋值运算符。赋值运算符比较特殊,我们要区分它与拷贝构造。当类与类进行赋值时,若类还没有进行初始化,将会调用拷贝构造;若已进行了初始化,将会调用赋值运算符。

        1,赋值运算符一般也要设置返回类型,一般返回 *this,因为我们要保证连续赋值的情况。

#include <iostream>
#include <assert.h>
using namespace std;
class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	// 赋值运算符重载
	Date& operator=(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
		return *this;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1(2023, 11, 9);
	Date d2, d3, d4;
	d4 = d3 = d2 = d1;//调用赋值运算符重载
	return 0;
}

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

class Date
{
public:
    Date(int year = 1900, int month = 1, int day = 1)
    {
        _year = year;
        _month = month;
        _day = day;
    }
    int _year;
    int _month;
    int _day;
};
// 赋值运算符重载成全局函数,注意重载成全局函数时没有this指针了,需要给两个参数
Date& operator=(Date& left, const Date& right)//出现错误,出现在全局中
{
    left._year = right._year;
    left._month = right._month;
    left._day = right._day;
    return left;
}

        原因:赋值运算符如果不显式实现,编译器会生成一个默认的。此时用户再在类外自己实现 一个全局的赋值运算符重载,就和编译器在类中生成的默认赋值运算符重载冲突了,因此,赋值运算符重载只能是类的成员函数。

        3,用户自己如果没有定义赋值运算符,编译器会生成一个默认赋值运算符重载,以浅拷贝的形式实现拷贝。内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值。

#include <iostream>
using namespace std;
class Time
{
public:
	Time()
	{
		_hour = 1;
		_minute = 1;
		_second = 1;
	}
	Time& operator=(const Time& t)
	{		
		_hour = t._hour;
		_minute = t._minute;
		_second = t._second;
		return *this;
	}
private:
	int _hour;
	int _minute;
	int _second;
};
class Date
{
private:
	// 基本类型(内置类型)
	int _year = 1970;
	int _month = 1;
	int _day = 1;
	// 自定义类型
	Time _t;
};
int main()
{
	Date d1;
	Date d2;
	d1 = d2;
	return 0;
}

d1 = d2运行的调试解图

        默认赋值运算符重载的原理跟默认拷贝构造一样,如果类中未涉及到资源空间的管理,赋值运算符是否实现都可以;一旦涉及到资源管理则必须要自己定义实现。

        (5)流操作符的重载。在C++程序中,我们也可实现插入操作符(<<)和提取操作符(>>)的重载。

        我们首先要认识ostream和istream。ostream用于处理输出流的类,类中定义了插入操作符(<<)来将数据写入输出流;istream是用于处理输入流的类。它定义了提取操作符(>>)来从输入流中提取数据。

定义样例:

在类的内部定义

第一个参数默认this指针

class Date
{
private:
    int _year = 2023;
    int _month = 10;
    int _day = 16;
};

//没有返回类型的情况

void operator<<(ostream& out);

void operator>>(istream& in);

//在类内部声明,在外部进行定义,也相当于在内部定义

void Date::operator<<(ostream& out);

void Date::operator>>(istream& in);

//返回类型为ostream和istream,这种情况为了支持连续输入输出的情况,因为连续输入输出需要有返回值去接收

ostream& operator<<(ostream& out);

istream& operator>>(istream& in);

在类的外部定义

没有默认参数,需要把类写入形参中

class Date
{
private:
    int _year = 2023;
    int _month = 10;
    int _day = 16;
};

//没有返回类型的情况

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

void operator>>(istream& out, const Date& d1);

//返回类型为ostream和istream,这种情况为了支持连续输入输出的情况,因为连续输入输出需要有返回值去接收

ostream& operator<<(ostream& out, const Date& d1);

istream& operator>>(istream& out, const Date& d1);

首先我们先观察以下代码:

#include<iostream>
using namespace std;
class Date
{
public:
	void operator<<(ostream& out) 
	{
		out << _year << "/" << _month << "/" << _day << endl;
	}
	void operator>>(istream& in)
	{
		in >> _year >> _month >> _day;
	}
private:
	int _year = 2023;
	int _month = 10;
	int _day = 16;
};
int main()
{
	Date d1;
	//cin >> d1;// 相当于cin.operator>>(d1);系统报错
	d1 >> cin;// 相当于d1.operator<<(cin);正常运行
	//cout << d1;// 相当于cout.operator<<(d1);系统报错
	d1 << cout;// 相当于d1.operator<<(cout);正常运行
	return 0;
}

        因为双操作数的运算符第一个参数是左操作数,第二个参数是右操作数,而在Date对象内部中,Date类对象默认占第一个位置,导致了以上情况的发生。

        要想解决以上的问题,保证代码的可读性,就改变参数的位置,显然这不能在类对象的内部定义,必须在外部定义。

无返回类型的使用(即不支持连续使用)

#include<iostream>
using namespace std;
class Date
{
public:
	int _year = 2023;
	int _month = 10;
	int _day = 16;
};
void operator<<(ostream& out, const Date& d)
{
	out << d._year << "/" << d._month << "/" << d._day << endl;
}
void operator>>(istream& in, Date& d)
{
	in >> d._year >> d._month >> d._day;
}
int main()
{
	Date d1;
	cin >> d1;// 相当于cin.operator>>(d1);正常运行
	cout << d1;// 相当于cout.operator<<(d1);正常运行
	return 0;
}

运用图解

有返回类型的使用(即支持连续使用)

#include<iostream>
using namespace std;
class Date
{
public:
	int _year = 2023;
	int _month = 10;
	int _day = 16;
};
ostream& operator<<(ostream& out, const Date& d)
{
	out << d._year << "/" << d._month << "/" << d._day << endl;
	return out;
}
istream& operator>>(istream& in, Date& d)
{
	in >> d._year >> d._month >> d._day;
	return in;
}
int main()
{
	Date d1, d2;
	cin >> d1 >> d2;// 从左到右连续进行,返回类型为输入流类的引用
	cout << d1 << endl << d2;// 从左到右连续进行,返回类型为输出流类的引用
	return 0;
}

这里要注意几个问题:

        1,当在外部定义时,因为是在外面访问成员对象的,因此权限必须设为public。

        2,在使用 “ >> ” 运算符时,因为是要对成员对象进行输入流给值的操作,所以类对象不能加用const。

        3,连续使用运算符操作相当于连续不断的赋值操作,这里需注意函数的返回类型。

总结一下:除流操作符以外的操作符一般是实现成员函数,“ >>,<< ”流运算要在外部实现,只有这样才能让流对象做第一个参数,实现可读性。还有就是要注意函数的返回类型,因为有了返回类型,才能实现连续使用运算符的操作。

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

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

相关文章

Django路由层解析

路由层(urls.py) Django的路由层是用于将URL映射到视图函数的机制。它用于确定请求URL&#xff08;HTTP请求&#xff09;应该被哪个视图函数处理。 Django的路由层包括两个部分&#xff1a; URL模式&#xff1a;匹配请求URL&#xff0c;决定应该使用哪个视图函数来处理请求。UR…

ChatGPT-3.5 插件推荐:语音输入,视频总结,联网检索

前言 GPT4 里是有内置的插件市场的&#xff0c;不过博主一直觉得自己对这个工具的使用还不够到位&#xff0c;现在购买升级版性价比不划算所以暂时还没有开。不过今天在学习使用的时候&#xff0c;发现 GPT3.5 也是可以通过网页插件方式进行升级扩展的&#xff0c;而且功能还比…

Redis05-集群方案

目录 Redis集群方案 主从复制 主从复制的基本原理 主从复制的工作流程 乐观复制 主从复制的优势 哨兵机制 哨兵的关键作用 服务状态监控 哨兵选举Master规则 分片集群 分片集群中的数据读写 数据写入 数据读取 一致性哈希和客户端分片 Redis集群方案 微服务时代…

AI在一定程度上能够使供应链变得不那么脆弱

供应链行业协会三菱重工今年进行的一项调查显示&#xff0c;供应链中的技能短缺是2000名供应链高管最关心的问题。联合包裹服务公司Ware2Go的供应链主管Kelton Kosik表示&#xff0c;在一系列全球贸易中断之后&#xff0c;对供应链人才——尤其是专注于技术领域的人才——的需求…

7个好用的可视化数据平台,让你的数据分析更高效率、高逼格

在信息爆炸的时代&#xff0c;数据是企业决策的重要依据。为了更高效率、更高逼格地进行数据分析&#xff0c;选择一个优秀的可视化数据平台至关重要。在众多可选项中&#xff0c;VeryReport报表软件脱颖而出&#xff0c;成为最好用的可视化数据平台之一&#xff0c;以下是其突…

openssh升级9.3p2

openssh升级9.3p2 openssh-rpms目录安装编译其他机器使用 将生成的rpm包传入响应服务器 openssh-rpms目录 github上有就是总是连接不上存百度网盘了 安装编译 unzip openssh-rpms-main.zip cd openssh-rpms-main/ yum -y groupinstall "Development Tools" yum -…

【数据结构】链表经典OJ题,常见几类题型(二)

目录 题型三&#xff1a;链表相交&#xff0c;找相交节点思路解析OJ题实例解题代码 题型四&#xff1a;链表带环&#xff0c;找入环节点思路解析OJ实例解题代码 题型三&#xff1a;链表相交&#xff0c;找相交节点 思路解析 看到这类题型首先要判断链表是否相交&#xff0c;而…

2022年06月 Python(五级)真题解析#中国电子学会#全国青少年软件编程等级考试

Python等级考试(1~6级)全部真题・点这里 一、单选题(共25题,每题2分,共50分) 第1题 Python中 print(“八进制{: o}”.format(12)) 正确的输出结果是?( ) A: 八进制:O B: 八进制:O14 C: 八进制14O D: 八进制14 答案:D 字符串的format()格式。 第2题 下列的程…

微服务拆分的一些基本原则

文章首发公众号&#xff1a;海天二路搬砖工 单一职责原则 什么是单一职责原则 单一职责原则原本是面向对象设计中的一个基本原则&#xff0c;它指的是一个类只负责一项职责&#xff0c;不要存在多于一个导致类变更的原因。 在微服务架构中&#xff0c;一个微服务也应该只负…

纯c语言模拟栈(初学必看)

1.栈的概念及其结构 栈是一种特殊的线性表&#xff0c;在栈这个结构里&#xff0c;越先存进去的数据越难取出来。 这个结构就像是一个只有一端有打开的容器&#xff0c;越先放进去的球越在底部&#xff0c;想要把底部的球拿出来&#xff0c;就必须先把前面的求拿出来。像这种”…

AYIT-ACM实验室发展历程

AYIT-ACM简介 ACM协会为你的梦想插上翅膀。 本院ACM协会成立于2012年 2008年开始小规模参加河南省竞赛 2014年成功实现金牌零突破 指导老师&#xff1a;孙高飞老师 安阳工学院计算机科学与信息工程学院ACM队是一支优秀的队伍&#xff0c;一支充满活力与激情的队伍&am…

vivado产生报告阅读分析-常规报告1

“ Report Utilization ” &#xff08; 使用率报告 &#xff09; 报告有助于从层级、用户定义的 Pblock 或 SLR 层面来分析含不同资源的设计的使用率。在流程中各步骤间使用 report_utilization Tcl 命令生成“ Utilization Report ”。 以下显示的报告详细信息适用于 Ultr…

【FPGA】十进制计数器 | 实现 4-bit 2421 十进制计数器 | 有限状态机(FSM)

目录 Ⅰ. 实践说明 0x00 十进制计数器 0x01 有限状态机&#xff08;FSM&#xff09; Ⅱ. 实践部分 0x00 4-bit 2421 十进制计数器 Ⅰ. 实践说明 0x00 十进制计数器 十进制计数器是一种以十进制运算的计数器&#xff0c;从 0 数到 9&#xff0c;然后返回 0 状态。由于它需…

【C语言数据结构————————二叉树】

文章目录 文章目录 一、什么是树 树的定义 树的种类 树的深度 树的基本术语 二、满二叉树 定义 满二叉树的特点 三、完全二叉树 定义 特点 四、二叉树的性质 五、二叉树的存储结构 顺序存储结构 链式存储结构 六、二叉树的基本操作 七、二叉树的创建 八、二叉树…

Vue3 ref函数和active函数

一、ref函数 我们在setup函数中导出的属性和方法虽然能够在模板上展示出来&#xff0c;但是并没有给属性添加响应式&#xff0c;因此&#xff0c;我们需要使用ref函数来为我们的数据提供响应式。 &#xff08;一&#xff09;引入ref函数 import { ref } from "vue"…

pychon/PIL/opencv/json学习过程中遇到的问题

1. 使用PIL.Image读取图片 注意&#xff1a;pytorch中对图像预处理是transforms的输入必须是PIL格式的文件&#xff0c;使用cv2读取的图片就按照第二条的代码处理&#xff08;3通道合并、归一化处理&#xff09; from PIL import Image img Image.open("test1.jpg"…

计算机组成原理之概述

概述 计组主要讲的是计算机的硬件实现方式。 机器字长 比如8080处理器&#xff0c;如果想处理16位数的整数运算&#xff0c;就需要执行两次。 可见&#xff0c;机器字长会影响到数据的处理速度。 计算机硬件的基本组成 早期的冯诺依曼机 冯诺依曼提出了“存储程序”的概念&…

【数据分享】2021-2023年我国主要城市逐月轨道交通运营数据

以地铁为代表的轨道交通是大城市居民的主要交通出行方式之一&#xff0c;轨道交通的建设和运营情况也是一个城市发展水平的重要体现。本次我们为大家带来的是2021-2023年我国主要城市的逐月的轨道交通运营数据&#xff01; 数据指标包括&#xff1a;运营线路条数&#xff08;条…

网络编程 初探windows编程

目录 一、什么是Winodws编程 二、开发环境搭建以及如何学习 三、VA助手安装 四、第一个Win32程序 五、窗口类句柄/窗口类对象 六、Winodws消息循环机制 七、Windows数据类型 一、什么是Winodws编程 Windows 编程指的是在 Microsoft Windows 操作系统上进行软件开发的过…

答题猜歌闯关流量主小程序开发

视频互动答题是一款微信小程序游戏&#xff0c;以视频互动的形式进行答题&#xff0c;内容涵盖广泛&#xff0c;包括天文地理、生活百科、历史文化、综艺娱乐、数理知识等。 用户可以通过答题获得红包兑换余额&#xff0c;并有机会赢得豪华奖品。 设计风格&#xff1a;设计风格…