今天你学C++了吗?——C++中的类与对象(第二集)

news2025/1/15 16:58:09


♥♥♥~~~~~~欢迎光临知星小度博客空间~~~~~~♥♥♥

♥♥♥零星地变得优秀~也能拼凑出星河~♥♥♥

♥♥♥我们一起努力成为更好的自己~♥♥♥

♥♥♥如果这一篇博客对你有帮助~别忘了点赞分享哦~♥♥♥

♥♥♥如果有什么问题可以评论区留言或者私信我哦~♥♥♥

✨✨✨✨✨✨ 个人主页✨✨✨✨✨✨

在前面一篇博客类与对象(第一集),我们简单了解了一下C++中的类与对象~接下来,我们要更加深层次的探讨C++中的类与对象~体会C++的魅力~准备好了吗~我们发车啦~🚗🚗🚗🚗🚗🚗

目录

类的默认成员函数

构造函数

析构函数

构造函数和析构函数的好处

拷贝构造函数


类的默认成员函数

前面我们提到了类里面有成员变量和成员函数,那么什么是默认成员函数呢?

定义:

默认成员函数就是用户(程序员)没有显式实现,编译器会自动生成的成员函数称为默认成员函数

⼀个类,我们不写的情况下编译器会默认生成以下6个默认成员函数

接下来,我们一个个来看~

构造函数

构造函数是特殊的成员函数,构造函数虽然名称叫构造,但是 构造函数的 主要任务 并不是开空间创建对象(我们常使用的局部对象是栈帧创建时,空间就已经开好),而是对象实例化时 初始化对象
这样看来,构造函数的本质是要替代我们以前Stack和Date类中写的Init(初始化)函数的功能。同时, 构造函数自动调用 特点就完美的替代的了Init函数调用。
构造函数的特点
1. 函数名与类名相同
函数名与类名相同,有利于编译器识别这个函数是用于类初始化的函数,而不是普通的成员函数
例:
class Date
{
public:
	//构造函数函数名与类名相同
	Date()
	{
		//构造函数
	}
};
2. 无返回值 。 (C++规定构造函数 不需要返回值,同时也不需要写void)
构造函数的存在是为了初始化对象,而不是返回数据~我们可以理解为规定~
3. 对象实例化时 系统会 自动调用对应的构造函数
(这就不需要我们手动调用构造函数了,更加方便,同时也避免了忘记初始化的情况~)
#include<iostream>
using namespace std;
class Date
{
public:
	//构造函数函数名与类名相同
	Date()
	{
		//构造函数
		cout << "Date()" << endl;
	}
};
int main()
{
	Date d1;//创建一个对象
	//对象实例化时系统会自动调用对应的构造函数
	return 0;
}

4. 构造函数可以重载
也就是说我们可以在同一个类里面写多个构造函数,来满足不同的初始化需求~
函数重载的要求是函数参数个数或者类型不同
#include<iostream>
using namespace std;
class Date
{
public:
	//构造函数函数名与类名相同
	Date()
	{
		//构造函数
		cout << "Date()" << endl;
	}
	// 构造函数可以重载
	Date(int y)
	{
		cout << "Date(int y)" << endl;
	}

};
int main()
{
	Date d1;//创建一个对象
	Date d2(2);
	return 0;
}

5. 如果类中没有显式定义构造函数,则C++编译器会自动生成⼀个无参的默认构造函数 ,如果用户显 式定义编译器将不再生成~
这样看来,编译器还是十分强大的,当我们忘记写构造函数,编译器自动生成一个没有参数的默认构造函数~

没有写构造函数,就会使用编译器生成的默认构造函数~

6. 无参构造函数、全缺省构造函数、我们不写构造时编译器默认生成的构造函数 ,都叫做 默认构造函数
三个函数有且只有一个存在 ,不能同时存在(默认构造函数只存在一个)
无参构造函数和全缺省构造函数虽然构成函数重载,但是调用时会存在歧义(编译器不知道调用哪一个)
》总结: 不传实参就可以调用的构造函数就叫默认构造函数
#include<iostream>
using namespace std;
class Date
{
public:
	Date()
	{
		cout << "Date()" << endl;
	}
	Date(int y = 2)
	{
		cout << "Date(int y)" << endl;
	}

};
int main()
{
	Date d1();//创建一个对象
	return 0;
}

因为编译器不知道调用哪一个,虽然没有报错,但是没有输出结果~这是存在歧义的~

7. 编译器生成的默认构造函数,对内置类型成员变量的初始化没有要求,也就是说是是否初始化是由编译器决定的,那么初始化的值也是不确定的
但是对于自定义类型成员变量必须调用这个成员变量的默认构造函数初始
如果这个成员变量,没有默认构造函数,那么就会报错,我们要初始化这个成员变量,需要使用初始化列表(后面的博客会讲解)才能解决
例:使用编译器自动生成的默认构造函数,初始化的值是不确定的~可以理解为随机值~

补充:

C++把类型分成 内置类型(基本类型) 自定义类型
内置类型就是语言提供的原始数据类型 如: int/char/double/指针
自定义类型就是我们使用class/struct/union等关键字自己定义的类型

我们来看看下面的代码:

#include<iostream>
using namespace std;
class Date
{
private:
	int _year;
	int _month;
	int _day;

public:
	void Print()
	{
		cout << _year << "年" << _month << "月" << _day << "日" << endl;
	}
};

int main()
{
	Date d1;//调用编译器生成的默认构造函数
	d1.Print();
	return 0;
}

我们可以看到年月日都是随机的,那么这肯定不是我们想要的~

所以如果这里我们使用编译器自动生成的默认构造函数,不能满足我们的需求~我们就需要自己写构造函数~比如日期类(我们肯定不希望日期是随机的的,未真正初始化的)

#include<iostream>
using namespace std;
class Date
{
private:
	int _year;
	int _month;
	int _day;
	
public:
	//构造函数
	//成员函数前面有一个隐含的this指针
	// Date* const this
	Date(int year,int month,int day)
	{
		_year = year;//相当于this->_year = year;
		_month = month;
		//this->_month = month;
		_day = day;
		//this->_day = day;
	}
	void Print()
	{
		cout << _year << "年" << _month << "月" << _day << "日" << endl;
	}
};

int main()
{
	Date d1(2024, 11, 11);//调用自己写的构造函数,满足我们的需求
	d1.Print();
	return 0;
}

又比如我们的栈~

#include<iostream>
using namespace std;
typedef int STDataType;
class Stack
{
public:
	//默认构造满足不了需求,需要自己写的构造函数
	Stack(int n = 4)
	{
		_a = (STDataType*)malloc(sizeof(STDataType) * n);
		if (nullptr == _a)
		{
			perror("malloc申请空间失败");
			return;
		}
		_capacity = n;
		_top = 0;
	}
	// ...
private:
	STDataType* _a;
	size_t _capacity;
	size_t _top;
};

那如果是使用两个栈实现一个队列,这种情况如果栈写了构造函数,就不需要写构造函数了~

#include<iostream>
using namespace std;
typedef int STDataType;
class Stack
{
public:
	//默认构造满足不了需求,需要自己写的构造函数
	Stack(int n = 4)
	{
		_a = (STDataType*)malloc(sizeof(STDataType) * n);
		if (nullptr == _a)
		{
			perror("malloc申请空间失败");
			return;
		}
		_capacity = n;
		_top = 0;
	}
	// ...
private:
	STDataType* _a;
	size_t _capacity;
	size_t _top;
};

// 两个Stack实现队列
class MyQueue
{
public:
	//编译器默认生成MyQueue的构造函数调用Stack的构造,完成了两个成员的初始化
private:
	Stack pushst;
	Stack popst;
};
int main()
{
	MyQueue mq;
	return 0;
}

这里栈的构造函数已经实现了队列的成员初始化~

总结:目前来看,大多数情况下需要自己写构造函数,如果一个类里面的成员全部是自定义类型,并且自定义类型的构造函数已经写好了,那么就不需要我们写构造函数了,比如两个栈实现一个队列,后续我们会了解更多的不需要自己写构造函数的情况

析构函数

了解了构造函数,我们就来看看与它作用相反的析构函数,既然构造函数是用来初始化的,那么析构函数就是用来对对象中的资源在生命周期结束时进行清理(类似于以前的Destory函数),比如手动申请的空间等等~

注意:
析构函数 不是完成对对象本身的销毁 ,只是 完成对象中资源的清理释放工作 ~比如局部对象是存在栈帧的,函数结束栈帧销毁,他就已经释放了,不需要我们管~像我们动态开辟的内存就需要我们手动释放资源
C++规定 对象在销毁时会自动调用析构函数 ,这样就可以 避免我们忘记释放资源而导致内存泄漏~

析构函数的特点

1. 析构函数名是 在类名前加上字符 ~,同时 函数名与类名相同~
2. 无参数无返回值 。 (同样不需要加void)
3. 对象生命周期结束时,系统会自动调用析构函数
例:
#include<iostream>
using namespace std;
class Date
{
public:
	//构造函数函数名与类名相同
	Date()
	{
		//构造函数
		cout << "Date()" << endl;
	}
	//析构函数
	~Date()
	{
		cout << "~Date()" << endl;
	}
};
int main()
{
	Date d1;//对象实例化
	return 0;
}

我们可以看到编译器自动调用了构造函数和析构函数~

4. ⼀个类只能有⼀个析构函数 。若 未显式定义,系统会自动生成默认的析构函数
(与前面构造函数类似~)
5. 跟构造函数类似,当我们不写 编译器自动生成的析构函数对内置类型成员不做处理 自定义类型的成员会调用他的析构函数释放资源
6. 我们显示写析构函数,对于自定义类型成员也会调用他的析构,也就是说 自定义类型成员无论什么情况都会自动调用析构函数,避免出现内存泄漏的情况~
7. 如果类中 没有申请资源时,析构函数可以不写 ,直接使用编译器生成的默认析构函数,如Date类;如果 默认生成的析构就足够使用,也不需要显示写析构 ,如MyQueue;但是 有资源申请时,一定要自己写析构,否则会造成资源泄漏 ,如Stack(需要我们释放动态申请的空间~)
例:
#include<iostream>
using namespace std;
typedef int STDataType;
class Stack
{
public:
	Stack(int n = 4)
	{
		_a = (STDataType*)malloc(sizeof(STDataType) * n);
		if (nullptr == _a)
		{
			perror("malloc申请空间失败");
			return;
		}
		_capacity = n;
		_top = 0;
	}
	//栈的析构函数必须自己写,释放资源
	~Stack()
	{
		cout << "~Stack()" << endl;
		free(_a);
		_a = nullptr;
		_top = _capacity = 0;
	}
private:
	STDataType* _a;
	size_t _capacity;
	size_t _top;
};
// 两个Stack实现队列
class MyQueue
{
public:
	//编译器默认生成MyQueue的析构函数调用了Stack的析构,释放的Stack内部的资源
	// 显示写析构,也会自动调用Stack的析构,这才是真正的释放资源
	~MyQueue()
	{
		cout << "~MyQueue" << endl;
	}
private:
	Stack pushst;
	Stack popst;
};
int main()
{
	Stack st;
	MyQueue mq;
	return 0;
}
8. ⼀个局部域的多个对象,C++规定 后定义的先析构,(后面会讲到这个内容)

构造函数和析构函数的好处

编译器有时候自动生成的默认构造函数和默认构造函数满足我们需求的情况下,可以减少我们的代码量(如两个栈实现队列不需要自己写析构函数,也不需要写构造函数)

编译器会自动调用构造函数和析构函数,就可以避免内存泄漏或者忘记初始化的情况~同时不用显示调用,也减少了我们的代码量~

拷贝构造函数

接下来就是这篇博客的重点了~拷贝构造函数~首先我们就需要知道拷贝构造函数是干什么的~

拷贝构造函数是用来通过一个已经初始化的对象去初始化另外一个新创建的对象~

拷贝构造函数 显示的第一个参数是自身类类型的引用 ,且任何额外的参数都有默认值~

1. 拷贝构造函数是构造函数的⼀个重载(函数名相同,都是类名)~

可以理解为拷贝构造函数是特殊的构造函数~

2. 拷贝构造函数的 参数只有⼀个 ,并且 必须是类类型对象的引用
使用传值方式编译器直接报错,因为语 法逻辑上会引发无穷递归调用~在传参的时候相当于也需要调用拷贝构造函数就回不来了~
例:
#include<iostream>
using namespace std;
class Date
{
public:
	//构造函数
	Date(int year,int month,int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	//拷贝构造函数-——特殊的构造函数
	Date(Date& d)
		//拷贝构造函数的参数只有⼀个,并且必须是类类型对象的引用
	{
		//用已经存在的对象去初始化新的对象
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
	void Print()
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1(2024, 11, 11);//d1调用构造函数
	Date d2(d1);//调用拷贝构造函数~用已经存在的对象去初始化新的对象
	Date d3 = d1;//同样是调用拷贝构造函数~用已经存在的对象去初始化新的对象
	d1.Print();
	d2.Print();
	d3.Print();
	return 0;
}
我们可以发现成功使用拷贝构造函数使用已经存在的对象去初始化新创建的对象~
3. C++规定 自定义类型对象进行拷贝行为必须调用拷贝构造 ,所以这里 自定义类型 传值传参 传值返回 (它们都会产生临时对象)都会调用拷贝构造完成~
注意:
传值返回会产生⼀个临时对象调用拷贝构造
传值使用引用返回,返回的是返回对象的别名,没有产生拷贝
如果 返回对象是⼀个当前函数局部域的局部对象,函数结束就销毁了,那么使用引用返回就有问题,这时的引用相当于⼀个野引用,类似⼀个野指针⼀样
传引用返回可以减少拷贝,但是 ⼀定要确保返回对象,在当前函数结束后还在,才能使用引用返回~
例:
#include<iostream>
using namespace std;
class Date
{
public:
	//构造函数(这里是全缺省参数,是默认构造函数的一种
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	//拷贝构造函数——已经存在的对象初始化一个新创建的对象
	Date(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
	Date(Date* d)
	{
		_year = d->_year;
		_month = d->_month;
		_day = d->_day;
	}
	void Print()
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};


//void Func1(Date d)//调用拷贝构造完成拷贝(产生了一个临时对象)
void Func1(Date& d)//使用引用传参优化,不需要拷贝构造,传自身,减少拷贝构造次数~
{
	cout << "&d" << endl;
	cout << &d << endl;
	cout << "d.Print()" << endl;
	d.Print();
}

Date Func2()//返回对象也会调用拷贝构造函数(相当于产生了一个临时对象)
//Date& Func2()//使用引用返回,不需要拷贝构造,返回自身,存在问题//err
//问题:Func2函数结束,tmp对象就销毁了,相当于了⼀个野引用
{
	Date tmp(2024, 2, 2);
	cout << "tmp.Print()" << endl;
	tmp.Print();
	return tmp;
}
int main()
{
	Date d1(2024, 11, 11);
	cout << "d1.Print()" << endl;
	d1.Print();
	//d1传值传参给d要调用拷贝构造完成拷贝,使用传引用传参可以减少拷贝
	cout << "&d1" << endl;
	cout << &d1 << endl;
	Func1(d1);

	
	Date ret = Func2();
	cout << "ret.Print()" << endl;
	ret.Print();
	return 0;
}

4. 若未显式定义拷贝构造,编译器会自动生成一个拷贝构造函数 ~
自动生成的拷贝构造 对内置类型成员变量会完成值拷贝/浅拷贝(⼀个字节⼀个字节的拷贝) 对自定义类型成员变量会调用他的拷贝构造
例:
#include<iostream>
using namespace std;
class Date
{
public:
	//构造函数
	Date(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void Print()
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1(2024, 11, 11);//d1调用构造函数
	Date d2(d1);//调用编译器自动生成的拷贝构造函数
	Date d3 = d1;//调用编译器自动生成的拷贝构造函数
	//自动生成的拷贝构造对内置类型成员变量会完成值拷贝/浅拷贝(⼀个字节⼀个字节的拷贝)
	d1.Print();
	d2.Print();
	d3.Print();
	return 0;
}

我们可以发现当我们没有显示写拷贝构造函数的时候,也完成了拷贝~这是因为使用了编译器自动生成的拷贝构造函数~实现了浅拷贝~

浅拷贝也就是把对象中的值拷贝过来~相当于共享同一份资源(比如内存空间、文件) ,那么如果对象中存在资源管理,比如动态开辟内存, 当多个对象共享同一份资源(内存空间)时,资源/空间释放的时候就会释放多次 (一个对象销毁时就已经释放了,其他对象不知道依然认为有效的~)这就会出问题~
还可能出现的问题是 一个对象修改时,会影响其他与它共享这个资源的对象 ~
深拷贝就可以很好的解决这个问题, 每一个对象都独立拥有一份资源(空间) ,这样就不会导致访问出错~
5.
Date这样的类 成员变量全是内置类型且没有指向什么资源 ,编译器自动生成的拷贝构造就可以完成,那么 不需要我们显示实现拷贝构造
但是像 Stack这样的类 ,虽然也都是内置类型,但是 _a指向了资源(申请了空间) ,编译器自动生成的拷贝构造完成的值拷贝/浅拷贝不符合我们的需求,所以 需要我们自己实现深拷贝(对指向的资源也进行拷贝)
MyQueue这样的类 ,内部主要是自定义类型 Stack成员, 编译器自动生成的的拷贝构造会调用Stack的拷贝构造 ,也 不需要我们显示实现MyQueue的拷贝构造
小技巧 区分是否需要显示写拷贝构造,可以 看⼀个类是否显示实现了析构并释放资源 如果是就 需要显示写拷贝构造,否则就不需要~
总结:类有申请占用资源,就需要我们自己写拷贝构造函数,避免多个对象共享一个资源
例:
#include<iostream>
using namespace std;
typedef int STDataType;
class Stack
{
public:
	Stack(int n = 4)
	{
		_a = (STDataType*)malloc(sizeof(STDataType) * n);
		if (nullptr == _a)
		{
			perror("malloc申请空间失败");
			return;
		}
		_capacity = n;
		_top = 0;
	}
	//涉及资源,需要显示写拷贝构造函数
	Stack(const Stack& st)
	{
		// 需要对_a指向资源创建同样大的资源再拷贝
		_a = (STDataType*)malloc(sizeof(STDataType) * st._capacity);
		if (nullptr == _a)
		{
			perror("malloc申请空间失败!!!");
			return;
		}
		
		memcpy(_a, st._a, sizeof(STDataType) * st._top);
		_top = st._top;
		_capacity = st._capacity;
	}

	void Push(STDataType x)
	{
		if (_top == _capacity)
		{
			int newcapacity = _capacity * 2;
			STDataType* tmp = (STDataType*)realloc(_a, newcapacity *
				sizeof(STDataType));
			if (tmp == NULL)
			{
				perror("realloc fail");
				return;
			}
			_a = tmp;
			_capacity = newcapacity;
		}
		_a[_top++] = x;
	}
	//析构函数
	~Stack()
	{
		cout << "~Stack()" << endl;
		free(_a);
		_a = nullptr;
		_top = _capacity = 0;
	}

private:
	STDataType* _a;
	size_t _capacity;
	size_t _top;
};

// 两个Stack实现队列
class MyQueue
{
public:
private:
	Stack pushst;
	Stack popst;
};
int main()
{
	Stack st1;
	st1.Push(1);
	st1.Push(2);
	// 如果Stack不显示实现拷贝构造,那么会使用编译器自动生成的拷贝构造完成浅拷贝
	// 会导致st1和st2⾥⾯的_a指针指向同⼀块资源,析构时会析构两次,程序崩溃

	Stack st2 = st1;
	MyQueue mq1;
	// MyQueue自动生成的拷贝构造,会自动调用Stack拷贝构造完成pushst/popst
	// 的拷贝,只要Stack拷贝构造实现了深拷贝,就没问题~
	MyQueue mq2 = mq1;
	return 0;
}

我们可以看到注释掉我们自己写的拷贝构造函数时,st1和st2的_a就是指向的同一块内存空间,资源共享了,就会出问题~

如果使用自己写的拷贝构造函数,就是不同的内存空间,就没有问题了~


♥♥♥本篇博客内容结束,期待与各位优秀程序员交流,有什么问题请私信♥♥♥

♥♥♥如果这一篇博客对你有帮助~别忘了点赞分享哦~♥♥♥

✨✨✨✨✨✨个人主页✨✨✨✨✨✨


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

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

相关文章

Anaconda3 2024 jupyter notebook 配置默认文件路径

我的版本如下&#xff1a; 第一步&#xff1a; 打开命令行anaconda prompt &#xff0c; 敲下面命令生成配置文件 jupyter notebook --generate-config 如下图&#xff1a; 修改配置jupyter_notebook_config.py 文件中搜索c.ServerApp.root_dir &#xff08; 对于 Anac…

【抓包专题】burpsuitProxifier小程序抓包

抓包系列文章 burpsuit&Proxifier&小程序抓包 抓包系列文章前言一、工具下载二、获取证书并安装到本地三、抓包测试 前言 抓包是进行渗透的第一步&#xff0c;包都抓不到&#xff0c;渗透就不要谈了&#xff0c;废话少说&#xff0c;开干 一、工具下载 Proxifier安装使…

springboot 异步 @Async 的日常使用及失效场景

文章目录 springboot 异步 Async 的日常使用引言一、Async 使用位置二、Async 使用三、注解 Async 失效的情况&#xff08;1&#xff09;调用同一个类中的异步方法&#xff08;内部调用&#xff09;&#xff08;2&#xff09;未使用 EnableAsync 注解&#xff08;3&#xff09;…

WebGIS技术汇总

WebGIS系统通常都围绕地图进行内容表达&#xff0c;但并不是有地图就一定是WebGIS&#xff0c;所以有必要讨论下基于Web的地图API分类及应用场景。 Web上的Map API主要分类如下几类&#xff1a; Charts&#xff1a;以D3.js&#xff0c;Echarts等为代表。LBS&#xff1a;以高德…

使用Vue3来实现一个倒计时器以及倒计时任务

本内容使用Vue3&#xff0c;以及element-plus辅助开发。 首先展示倒计时器的功能&#xff1a; 手动设置倒计时器的倒计时时间开始倒计时按钮暂停倒计时按钮重新开始倒计时按钮 其次展示倒计时任务管理界面功能&#xff1a; 创建倒计时任务选择任务并进行倒计时删除任务 目录 一…

VMware Workstation 虚拟机运行卡顿解决方案

前言 由于我们网站主力是模拟器多开&#xff0c;VMware虚拟机纯属我个人使用的经验&#xff0c;仅供参考。顺带一提&#xff1a;多开鸭的系统精简掉的是Hyper-V&#xff0c;跟VMware完全没有任何关系&#xff0c;Hyper-V跟雷电这些模拟器会冲突&#xff0c;但是移除之后不会影…

GitLab|应用部署

创建docker-compose.yaml文件 输入docker-compose配置 version: 3.8 services:gitlab:image: gitlab/gitlab-ce:15.11.2-ce.0restart: alwayscontainer_name: gitlab-ceprivileged: truehostname: 192.168.44.235environment:TZ: Asia/ShanghaiGITLAB_OMNIBUS_CONFIG: |exter…

ssm182在线作业管理系统的设计与实现+vue(论文+源码)_kaic

设计题目&#xff1a;在线作业管理系统的设计与实现 摘 要 网络技术和计算机技术发展至今&#xff0c;已经拥有了深厚的理论基础&#xff0c;并在现实中进行了充分运用&#xff0c;尤其是基于计算机运行的软件更是受到各界的关注。加上现在人们已经步入信息时代&#xff0c;所…

LeetCode-632. Smallest Range Covering Elements from K Lists [C++][Java]

目录 题目描述 解题思路 【C】 【Java】 LeetCode-632. Smallest Range Covering Elements from K Listshttps://leetcode.com/problems/smallest-range-covering-elements-from-k-lists/description/ 题目描述 You have k lists of sorted integers in non-decreasing o…

指针的奥秘:深入探索内存的秘密

前言 在计算机编程的广阔天地中&#xff0c;指针作为一种独特的数据类型&#xff0c;它不仅是C语言的核心&#xff0c;也是理解计算机内存管理的基石。指针的概念虽然强大&#xff0c;但对于初学者来说&#xff0c;它常常是学习过程中的一个难点。本文旨在揭开指针的神秘面纱&a…

⭐ Unity 资源管理解决方案:Addressable_ Demo演示

一、使用Addressable插件的好处&#xff1a; 1.自动管理依赖关系 2.方便资源卸载 3.自带整合好的资源管理界面 4.支持远程资源加载和热更新 二、使用步骤 安装组件 1.创建资源分组 2.将资源加入资源组 3.打包资源 4.加载资源 三种方式可以加载 using System.Collections…

红日靶场-4

环境搭建 我们这里会拿到三台主机&#xff0c;一台web主机&#xff0c;一台win7主机&#xff0c;一台DC主机 机器密码 WEB主机 ubuntu:ubuntu WIN7主机 douser:Dotest123 (DC)WIN2008主机 administrator:Test2008 登陆后需修改密码&#xff0c;我这里修改为1qazWSX 网络配…

使用八爪鱼爬虫抓取汽车网站数据,分析舆情数据

我是做汽车行业的&#xff0c;可以用八爪鱼爬虫抓取汽车之家和微博上的汽车文章内容&#xff0c;分析各种电动汽车口碑数据。 之前&#xff0c;我写过很多Python网络爬虫的案例&#xff0c;使用requests、selenium等技术采集数据&#xff0c;这次尝试去采集小米SU7在微博、汽车…

具有多个表盘、心率传感器、指南针和游戏的 DIY 智能手表

在此&#xff0c;我们将使用所学到的知识&#xff0c;结合使用硬件和软件组件从头开始创建自己的智能手表。在项目的这一部分&#xff0c;您将被指导完成组装硬件组件、设置软件以及配置智能手表的设置和功能的过程。到本项目结束时&#xff0c;您将拥有一款功能齐全的智能手表…

Django+Nginx+uwsgi网站Channels+redis+daphne多人在线聊天实现粘贴上传图片

在DjangoNginxuwsgi网站Channelsredisdaphne多人在线的基础上&#xff08;详见DjangoNginxuwsgi网站使用Channelsredisdaphne实现简单的多人在线聊天及消息存储功能-CSDN博客&#xff09;&#xff0c;实现在输入框粘贴或打开本地图片&#xff0c;上传到网站后返回图片路径&…

[ubuntu]编译共享内存读取出现read.c:(.text+0x1a): undefined reference to `shm_open‘问题解决方案

问题log /tmp/ccByifPx.o: In function main: read.c:(.text0x1a): undefined reference to shm_open read.c:(.text0xd9): undefined reference to shm_unlink collect2: error: ld returned 1 exit status 程序代码 #include <stdio.h> #include <stdlib.h> #…

Otter 安装流程

优质博文&#xff1a;IT-BLOG-CN 一、背景 随着公司的发展&#xff0c;订单库的数据目前已达到千万级别&#xff0c;需要进行分表分库&#xff0c;就需要对数据进行迁移&#xff0c;我们使用了otter&#xff0c;这里简单整理下&#xff0c;otter 的安装过程&#xff0c;希望对…

wsl2的Ubuntu18.04安装ros和anaconda

参考&#xff1a;超详细 WSL2 安装 ros 和 anaconda_wsl2安装anaconda-CSDN博客 一.安装ros 1. 更换系统源 输入 wget http://fishros.com/install -O fishros && . fishros 和上面的链接一样&#xff0c;依次输入5-2-1 2. 安装ros 输入 wget http://fishros.c…

鸿蒙NEXT开发案例:字数统计

【引言】 本文将通过一个具体的案例——“字数统计”组件&#xff0c;来探讨如何在鸿蒙NEXT框架下实现这一功能。此组件不仅能够统计用户输入文本中的汉字、中文标点、数字、以及英文字符的数量&#xff0c;还具有良好的用户界面设计&#xff0c;使用户能够直观地了解输入文本…

【经典】抽奖系统(HTML,CSS、JS)

目录 1、添加参与者 2、多次添加 3、点击抽奖 功能介绍&#xff1a; 使用方法&#xff1a; 完整代码&#xff1a; 一个简单但功能强大的抽奖系统的示例&#xff0c;用于在网页上实现抽奖。 1、添加参与者 2、多次添加 3、点击抽奖 功能介绍&#xff1a; 参与者添加&…