【C++】类和对象-深度剖析默认成员函数-上

 
> 🍃 本系列为初阶C++的内容,如果感兴趣,欢迎订阅🚩
> 🎊个人主页:[小编的个人主页])小编的个人主页
>  🎀   🎉欢迎大家点赞👍收藏⭐文章
> ✌️ 🤞 🤟 🤘 🤙 👈 👉 👆 🖕 👇 ☝️ 👍


目录

🐼类的默认成员函数

⭐️概念:

 🐼构造函数

⭐️概念:

⭐️特点:

 🐼 析构函数

⭐️概念

⭐️特点:

  🐼拷贝构造函数

⭐️概念

⭐️剖析:


🐼类的默认成员函数

⭐️概念:

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

在C++中有6个默认成员函数:构造函数(包括无参和带参)、析构函数、拷贝构造函数、赋值运算符重载、const成员函数以及取地址操作符

这些默认成员函数前四个比较重要。它们在类的创建、初始化、清理和资源管理中起着关键作用。

 🐼构造函数

 我们先来看看这样一个例子:

#include<iostream>
using namespace std;
class Date
{
public:void Init(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;d1.Init(2024, 11, 14);d1.Print();Date d2;d2.Init(2022, 11, 14);d2.Print();
}

创建对象d1,d2,在调用Print方法之前,我们都需要分别先调用Init方法,我们能不能想个方法,在对象创建时,就可以完成初始化,即d1,d2的初始化信息导进去。这就需要构造函数来完成

⭐️概念:

构造函数是特殊的成员函数,在创建类对象时由编译器自动调用,用于在创建对象时初始化对象。

🐟需要注意的是,构造函数虽然名称叫构造,但是构造函数的主要任务并不是开空间创建对象(我们常使用的局部对象是栈帧创建时,空间就开好了),而是对象实例化时初始化对象也就是在对象诞生时,就给对象适合的值,进行实例化,这样对象刚出生,就给成员变量一个合适的初始值。并且在对象生命周期只初始化一次

例如:在创建对象d1,d2时,就已经对成员变量   _year; _month; _day一个合适的初始值,不需要再单独调用Init函数了。

⭐️特点:

  1. 构造函数名与类名相同
  2. 构造函数无返回值。(返回值啥都不需要给,也不需要写void,不要纠结,C++规定如此)
  3. 对象实例化时系统会自动调用对应的构造函数。
  4. 构造函数可以重载。也就是构造函数可以有多个,具体调用哪个看参数。
  5. 如果类中没有显式定义构造函数,则C++编译器会自动生成⼀个无参的默认构造函数,⼀旦用户显式定义编译器将不再生成。
  6. 不传实参就可以调用的构造就叫默认构造,无参构造函数全缺省构造函数、我们不写构造时编译器默认生成的构造函数都叫做默认构造函数但是这三个函数有且只有⼀个存在,不能同时存在。无参构造函数和全缺省构造函数虽然构成函数重载,但是调用时会存在歧义。

举个例子:

#include<iostream>
using namespace std;
class Date
{
public://有参构造函数/*Date(int year, int month, int day){_year = year;_month = month;_day = day;}*/默认构造函数全缺省Date(int year = 1, int month =1 , int day= 1){_year = year;_month = month;_day = day;}//无参//Date()//{//	_year = 2024;//	_month = 11;//	_day = 14;//}void Print(){cout << _year << '-' << _month << '-' << _day << endl;}
private:int _year;int _month;int _day;
};int main()
{Date d1;d1.Print();Date d2(2024, 11, 14);d2.Print();
}

🐋我们创建一个对象d1的同时,这里调用默认构造函数,编译器自动调用构造函数;创建了对象d2,这里调用带参数的构造函数。我们这里没有显示定义Init函数来对我们的对象初始化,是因为在创建对象时已经完成了对对象的初始化

运行结果:

注意:如果通过无参构造函数创建对象时,对象后面不跟括号,如Date d1()这是错误写法,否则编译器无法  区分这里是函数声明还是实例化对象 会报错: warning C4930: “Date d3(void)”: 未调用原型函数(是否是有意⽤变量定义的?)

🌏如果我们不显示写:编译器对内置类型成员变量的初始化没有要求,也就是说是是否初始化是不确定的,看编译器。如果我们把默认构造函数去除,调用编译器自已的默认构造函数,vs运行结果:

🌴对于自定义类型(struct class)成员变量,要求调用这个成员变量的默认构造函数初始化

比如两个栈(Stack)实现队列(MyQueue),其中自定义类型Stack为成员变量,这就需要我们对Stack进行初始化,而MyQueue会自动调用这个成员变量(Stack)的默认构造函数初始化,我们不需要显示写

如:

#include <assert.h>
#include<iostream>
using namespace std;
class Stack
{
public:Stack(int n = 4){int* tmp = (int*)malloc(sizeof(int)*n);if (tmp == nullptr){perror("malloc fail");return;}capacity = n;arr = tmp;cout << "调用Stack默认构造函数" << endl;}private:int* arr;size_t top;size_t capacity;
};//两个栈实现队列
//这里自定义类型stack,默认构造函数已经实现,myqueue可以不写默认构造函数
// 编译器会自动调用自定义类型的默认构造函数
class MyQueue
{
public:// 不需要写构造,默认生成就可以用
private:Stack pushlit;Stack poplit;
};int main()
{MyQueue q1;return 0;
}
解释

在上述例子中,我们实现了Stack的默认构造函数,而MyQueue没有实现构造函数,这并不是说MyQueue调用编译器自动生成的默认构造函数,而是编译器会自动调用自定义类型的默认构造函数。

总结:这里自定义类型stack,默认构造函数已经实现,myqueue可以不写默认构造函数。

运行结果:

调试观察:

我们创建了一个MyQueue的类对象q1,q1有两个Stack类型的成员变量pushlit,poplit,MyQueue会自动调用这个成员变量(Stack)的默认构造函数初始化

 🐼 析构函数

🌟如果说构造函数是是在对象诞生时给对象实例化。那么析构函数就是完成对象销毁时对对资源的清理和释放

⭐️概念

析构函数与构造函数功能相反,析构函数不是完成对对象本身的销毁,比如局部对象是存在栈帧的, 函数结束栈帧销毁,他就释放了,不需要我们管,C++规定对象在销毁时会自动调用析构函数,完成对象中资源的清理释放工作

⭐️特点:

  1. 析构函数名是在类名前加上字符~;
  2. 无参数无返回值。(这里跟构造类似,也不需要加void)
  3. ⼀个类只能有⼀个析构函数。若未显式定义,系统会自动生成默认的析构函数。不能析构两次,否则可能造成空间的重复释放;
  4. 对象生命周期结束时,系统会自动调用析构函数。

举例:

class  animal
{
public:animal(){std::cout << "自动调用构造函数" << std::endl;}~animal(){std::cout << "自动调用析构函数" << std::endl;}private:};
int main()
{animal dog;std::cout << "对象销毁" << std::endl;return 0;
}

运行结果:

在上述例子中我们定义了一个动物类,并创建了一个对象dog,我们发现,如果我们显示的定义构造函数和析构函数,编译器会自动调用我们生成的构造函数和析构函数在对象创建时调用构造函数,在对象销毁时,编译器会自动调用析构函数

跟构造函数类似,我们不写编译器自动生成的析构函数对内置类型成员不做处理,自定类型成员会调用他的析构函数。  

如:


#include<iostream>class  animal
{
public:animal(){std::cout << "自动调用构造函数" << std::endl;}~animal(){std::cout << "自动调用析构函数" << std::endl;}private:};
class fish
{
public:~fish(){std::cout << "自动调用析构函数fish" << std::endl;}
private:animal carp;//鲤鱼animal  eel;//鳗鱼
};int main()
{fish f1;std::cout << "对象销毁" << std::endl; return 0;
}

运行结果:

🌲我们在上述又新定义了一个鱼类🐋,鱼类的成员变量都是animal类的,这时候我们不需要显示的在fish中写析构函数,因为编译器会自动调用自定义类型(animal)的析构函数。

🌏如果我们显示写,编译器也会先调用他的析构函数,再调用自定义类型的析构函数。就是我们显示写析构函数,对于自定义类型成员也会调用他的析构,则先调用fish的析构函数,再调用两个自定义成员变量的析构函数,也就是说自定义类型成员无论什么情况都会自动调用析构函数。

🌿如果类中没有申请资源时,析构函数可以不写,直接使用编译器生成的默认析构函数,如Date;如 果默认生成的析构就可以用,也就不需要显示写析构,如MyQueue;但是有资源申请时,⼀定要自已写析构,否则会造成资源泄漏,如Stack

下面代码是上面文字的解释:

class Date
{
public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}//Date类没有申请的资源,可以不写析构函数
private:int _year;int _month;int _day;
};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;std::cout << "自动调用构造函数" << std::endl;}//Stack中有申请的资源,析构函数一定要写~Stack(){cout << "~Stack()" << endl;free(_a);_a = nullptr;_top = _capacity = 0;std::cout << "自动调用析构函数" << std::endl;}
private:STDataType* _a;size_t _capacity;size_t _top;
};int main()
{Stack s1;std::cout << "对象销毁" << std::endl; return 0;
}

解释

🌲析构函数的功能类比我们之前Stack实现的Destroy功能,而像Date没有 Destroy,其实就是没有资源需要释放,所以严格说Date是不需要析构函数的

注意:⼀个局部域的多个对象,C++规定后定义的先析构

🔍总结:我们发现有了构造函数和析构函数确实方便了很多,不会再忘记调用nit和Destory函数了,也方便了不少

构造函数基本都需要,析构函数是有对象有资源要释放时需要,否则,可以不显示定义。如果没有显示的写构造函数和析构函数,编译器会自动生成默认生成的构造函数和析构函数,在对象创建和销毁时调用时,会自动调用。

  🐼拷贝构造函数

🌟在我们现实生活中,会有双胞胎。在C++的世界里,也会有对象的双胞胎,比如创建了一个对象d1,再拷贝另一个与d1完全相同的对象d2即用d1初始化一个对象化d2,这就需要另一个默认成员函数,就是拷贝构造函数.

⭐️概念

🌲如果⼀个构造函数的第⼀个参数是自身类类型的引用(&),一般是(const)引用,且任何额外的参数都有默认值,则此构造函数也叫做拷贝构造函数,也就是说拷贝构造是⼀个特殊的构造函数,是构造函数的重载

⭐️剖析:

我们来看下面这个例子再来解释拷贝构造函数一些问题和要求:


#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){this->_year = d._year;this->_month = d._month;this->_day = d._day;}//错误写法/*Date( Date d){this->_year = d._year;this->_month = d._month;this->_day = d._day;}*/void Print(){cout << _year << '-' << _month << '-' << _day << endl;}
private:int _year;int _month;int _day;
};int main()
{Date d1(2024,11,14);Date d2(d1);d1.Print();d2.Print();
}

解释

🌾我们这里创建了一个对象d1,并调用默认构造函数的全缺省进行初始化。我们这里又想创建一个与d1完全相同的对象d2(Date d2(d1));,我们在之前学习了this指针,其实,这里完整的实参是Date d2(&d2,d1),形参是Date(const Date* this,const Date& d);实现了将d1一一赋值给d2(这里拷贝构造函数中的this指针可以省去,这里仅是为了理解),这样我们就创建了一个以d1为模版的d2。


我们现在来解决几个问题:

👀为什么拷贝函数的第⼀个参数是自身类类型的引用(&)?

拷贝构造函数的参数只有⼀个且必须是类类型对象的引用,使用传值方式编译器直接报错,因为语法逻辑上会引发无穷递归调用

C++规定自定义类型对象进行拷贝行为必须调用拷贝构造,所以这里传值传参要调用拷贝构造

🌾如果直接将d1传过去,d1是自定义类型的对象,所以这里涉及传值传参要调必须先调用拷贝构造函数,而如果这样的写法,调用拷贝构造函数又是传值传参,就又要先调用拷贝构造函数,形成了逻辑递归死循环。如图:

即:如果是传值传参,必须先调用拷贝构造函数,而拷贝构造函数又会引起传值传参,又要调用新的拷贝构造

这里直接用&引用,就不会引发传值,因为引用在语法层d就是d1,没有额外申请空间,就不会引发传值调用,就不会调用新的拷贝构造函数。所以只有第⼀个参数是自身类类型的引用(&)的构造函数是拷贝构造函数

👀为什么拷贝函数的第⼀个参数前要加const修饰?

因为在拷贝过程中,我们只希望原拷贝对象(d2)拷贝复制被拷贝对象(d1),不希望原拷贝对象(d1)发生改变,如果不加const,很容易就将原拷贝对象修改,这样做,是希望在拷贝过程中,不改变原拷贝对象(d1),通常,我们写拷贝构造函数时都要在第⼀个参数引用(&)前+(const)加强代码的健壮性

👀可否直接用将d1的地址传过去,形参指针来接收呢?

理论上是可以的。

代码:

//指针接收//这就不是拷贝函数,而是构造函数
//Date d2(&d1)
Date(Date* d)
{cout << "Date(Date* d)" << endl;_year = d->_year;_month = d->_month;_day = d->_day;
}

🌸不过这样写,虽然也能完成,但也不符合C++拷贝构造函数的定义,这就不是拷贝构造函数了,而是普通的构造函数,这样写Date(const Date& d)才是拷贝构造函数,而不是指针。

👀只要进行传值传参的自定义类型对象进行拷贝行为必须调用拷贝构造?

我们以下面这个例子为例:


Date fun1()
{Date d3;return d3;
}//传值传参调用拷贝构造
void fun2(Date d)
{}
int main()
{Date d4 = fun1();fun2(d4);
}

🌸调用fun1时,创建了对象d3并返回,在C++中,我们知道,传值返回,要先拷贝在一个临时变量中,所以就调用了拷贝构造函数;在fun2中,实参和形参的传值传参就会先调用拷贝构造函数。总结,在自定义类型的传值传参,或传值返回,代价会更大,因为都会先调用拷贝构造

我们还要知道拷贝构造函数的两种写法

Date d1;
Date d2(d1);
Date d2 = d1;//这种方式也表示拷贝构造

我们再来看下面一个例子,引用返回对象的易错点:


// Date Func2()
Date& Func2()
{Date tmp(2024, 7, 5);tmp.Print();return tmp;
}int main()
{// Func2返回了⼀个局部对象tmp的引用作为返回值 // Func2函数结束,tmp对象就销毁了,相当于了⼀个野引用Date d1 = Func2();d1.Print();
}

🌿我们先区分:传值返回会产生一个临时对象调用拷贝构造,传值引用返回,返回的是返回对象的别名(引用),没有产生拷贝。但是如果返回对象是⼀个当前函数局部域的局部对象,函数结束就销毁了,那么使用引用返回是有问题的,这时的引用相当于⼀个野引用,类似⼀个野指针⼀样。虽然传引用返回可以减少拷贝,但是⼀定要确保返回对象,在当前函数结束后还在,才能用引用返回

🌿若未显式定义拷贝构造,编译器会生成自动生成拷贝构造函数。自动生成的拷贝构造对内置类型成员变量会完成值拷贝/浅拷贝(⼀个字节⼀个字节的拷贝),对自定义类型成员变量会调用他的拷贝构造。

对于内置类型成员变量的浅拷贝:

#include<iostream>
using namespace std;class Date
{
public://	//	默认构造函数//	全缺省//这里可以任意选择一种构造函数进行初始化Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}//我们不显示写拷贝构造void Print(){cout << _year << '-' << _month << '-' << _day << endl;}
private:int _year;int _month;int _day;
};int main()
{Date d1;Date d2(d1);d1.Print();d2.Print();return 0;
}

运行结果:

🌻我们这里没有显示的写拷贝构造函数,但是发现d2还是拷贝了d1。因为在C++中,如果我们不写拷贝构造函数,自动生成的拷贝构造对内置类型成 员变量会完成值拷贝/浅拷贝(⼀个字节⼀个字节的拷贝),对自定义类型成员变量会调用他的拷贝构造。


下面我们再来看一个拷贝对象有资源时的深拷贝,如栈,向堆上开辟空间,就属于有资源的拷贝,这时候如果再发生浅拷贝,会有冲突,如:

#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;}void Pop(){_a[_top - 1] - 1;_top--;}//取栈顶元素STDataType Top(){return _a[_top - 1];}~Stack(){cout << "~Stack()" << endl;free(_a);_a = nullptr;_top = _capacity = 0;}
private:STDataType* _a;size_t _capacity;size_t _top;
};int main()
{Stack st1;st1.Push(1);st1.Push(2);st1.Push(3);st1.Push(4);Stack st2(st1);//st1和st2指向同一片空间st1.Pop();st1.Pop();cout << st2.Top()<< endl;
}

像Stack这样的类,虽然也都是内置类型,但 是_a指向了资源,编译器自动生成的拷贝构造完成的值拷贝/浅拷贝不符合我们的需求😞,所以需要我们自已实现深拷贝(对指向的资源也进行拷贝😊。

🌻如果编译器自动生成的拷贝构造完成的值拷贝/浅拷贝来解决深拷贝会造成两个问题,(1)由于st1,str2的成员变量_a都指向同一片空间,对st1对象的改变就会影响到st2,(2),对象st1,st2销毁编译器都会自动析构函数,导致同一片内存空间被释放两次,造成内存异常访问。所以,对于有资源的类,我们需要我们自已显示完成深拷贝(拷贝构造函数)。

st1,st2指向同一片内存空间:

💫我们再来看第二个:对自定义类型成员变量会调用他的拷贝构造。如下述例子:

#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;}void Pop(){_a[_top - 1] - 1;_top--;}//取栈顶元素STDataType Top(){return _a[_top - 1];}~Stack(){cout << "~Stack()" << endl;free(_a);_a = nullptr;_top = _capacity = 0;}
private:STDataType* _a;size_t _capacity;size_t _top;
};class MyQueue
{
private:Stack _pushst;Stack _popst;
};int main()
{// MyQueue⾃动⽣成的拷⻉构造,会⾃动调⽤Stack拷⻉构造完成pushst/popst // 的拷⻉,只要Stack拷⻉构造⾃⼰实现了深拷⻉,就没问题 MyQueue q1;MyQueue q2(q1);
}

💫像MyQueue这样的自定义类型内部主要是自定义类型Stack成员,编译器自动生成的拷贝构造会调用Stack的拷贝构造,也不需要我们显示实现MyQueue的拷贝构造。这一点和构造函数和析构函数相似。

这里自动调用Stack拷贝构造函数代码

调试结果:

✌️这里有一个小技巧,如果一个类显示实现了析构并释放资源,那么他就需要显示写拷贝构造,否则就不需要。 

对于类中成员变量都是内置类型的,如果有资源,拷贝函数需要,否则不需要,对于自定义类型,拷贝函数会自动调用它的拷贝构造函数。

感谢你看到这里,如果觉得本篇文章对你有帮助,点赞👍收藏 ⭐️吧,你的支持就是我更新的最大动力。⛅️🌈 ☀️ 

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

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

相关文章

Web性能优化:从基础到高级

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 Web性能优化&#xff1a;从基础到高级 Web性能优化&#xff1a;从基础到高级 Web性能优化&#xff1a;从基础到高级 引言 基础优…

当 docker-compose.yaml 文件部署时,Dify 线上版本升级过程

如果线上 Dify 是通过 docker-compose.yaml 文件部署的&#xff0c;那么当 Dify 版本升级时该如何操作呢&#xff1f;官方已经给出了 Docker compose 和 Source Code 两种方式。相对而言&#xff0c;前者更简单些&#xff0c;至少不需要安装依赖包和迁移数据库文件。为了更加具…

如何让手机ip变成动态

在数字化浪潮中&#xff0c;手机已成为我们日常生活中不可或缺的一部分。无论是浏览网页、使用社交媒体还是进行在线购物&#xff0c;手机都扮演着举足轻重的角色。然而&#xff0c;在享受网络带来的便利时&#xff0c;我们也需要关注网络安全和隐私保护。静态IP地址可能让手机…

vue3 如何调用第三方npm包内部的 pinia 状态管理库方法

抛砖引玉: 如果在开发vue3项目是, 引用了npm第三方包 ,而且这个包内使用了Pinia 状态管理库,那我们如何去调用 npm内部的 Pinia 状态管理库呢? 实际遇到的问题: 今天在制作npm包时遇到的问题,之前Vue2版本的时候状态管理库用的Vuex ,当时调用npm包内的状态管理库很简单,直接引…

Linux笔记---调试工具GDB(gdb)

1. gdb的概念 GDB&#xff0c;全称GNU Debugger&#xff0c;是一个功能强大的开源调试工具&#xff0c;广泛用于Unix和类Unix系统&#xff0c;以及Microsoft Windows和macOS平台。GDB允许开发者在程序执行过程中查看内部运行情况&#xff0c;帮助定位和修复程序中的错误。 gd…

编译器gcc/g++

gcc 只用来编译C g 编译C/C 1.预处理&#xff08;进行宏替换/去注释/条件编译/头文件展开等&#xff09; 先创建 code.c 文件 -E --> 从现在开始&#xff0c;进行程序的翻译&#xff0c;一旦预处理做完&#xff0c;就停下来 -o --> 表明 -o 后面的文件名称 code…

一.安装版本为19c的Oracle数据库管理系统(Oracle系列)

1.数据库版本信息&#xff1a; 版本信息&#xff1a; 或者直接由命令查出来&#xff1a; 2.操作系统的版本信息 3.安装包下载与上传 可以去oracle官网下载也可以从其他人的百度网盘链接中下载&#xff1a; 使用xftp工具或者其他的工具&#xff08;mobaxterm&#xff09;上传到l…

DimensionX 部署笔记

目录 生成视频用CogVideoX-5b-I2V 推理代码&#xff1a; DimensionX 生成视频用CogVideoX-5b-I2V 推理代码&#xff1a; 可以生成&#xff0c;从左向右旋转的&#xff0c;也可以生成从上往下旋转的&#xff1a; import torch from diffusers import CogVideoXImageToVideo…

uni-app移动端与PC端兼容预览PDF文件

过程遇到的问题 1、如果用的是最新的版本的pdfjs的话&#xff0c;就会报Promise.withResolvers 不是一个方法的错误&#xff0c;原因是Promise.withResolvers是ES15新特性&#xff0c;想了解可参考链接&#xff0c;这里的解决方案是将插件里的涉及到Promise.withResolvers的地…

Node.js | Yarn下载安装与环境配置

一、安装Node.js Yarn 是 Node.js 下的包管理工具&#xff0c;因此想要使用 Yarn 就必须先下载 Node.js。 推荐参考&#xff1a;Node.js | npm下载安装及环境配置教程 二、Yarn安装 打开cmd&#xff0c;输入以下命令&#xff1a; npm install -g yarn检查是否安装成功&…

开源TTS语音克隆神器GPT-SoVITS_V2版本地整合包部署与远程使用生成音频

文章目录 前言1.GPT-SoVITS V2下载2.本地运行GPT-SoVITS V23.简单使用演示4.安装内网穿透工具4.1 创建远程连接公网地址 5. 固定远程访问公网地址 前言 本文主要介绍如何在Windows系统电脑使用整合包一键部署开源TTS语音克隆神器GPT-SoVITS&#xff0c;并结合cpolar内网穿透工…

[Docker#11] 容器编排 | .yml | up | 实验: 部署WordPress

目录 1. 什么是 Docker Compose 生活案例 2. 为什么要使用 Docker Compose Docker Compose 的安装 Docker Compose 的功能 使用步骤 核心功能 Docker Compose 使用场景 Docker Compose 文件&#xff08;docker-compose.yml&#xff09; 模仿示例 文件基本结构及常见…

鸿蒙NEXT应用示例:切换图片动画

【引言】 在鸿蒙NEXT应用开发中&#xff0c;实现图片切换动画是一项常见的需求。本文将介绍如何使用鸿蒙应用框架中的组件和动画功能&#xff0c;实现不同类型的图片切换动画效果。 【环境准备】 电脑系统&#xff1a;windows 10 开发工具&#xff1a;DevEco Studio NEXT B…

【spring 】Spring Cloud Gateway 的Filter学习

介绍和使用场景 Spring Cloud Gateway 是一个基于 Spring Framework 5 和 Project Reactor 的 API 网关&#xff0c;它旨在为微服务架构提供一种简单而有效的方式来处理请求路由、过滤、限流等功能。在 Spring Cloud Gateway 中&#xff0c;Filter 扮演着非常重要的角色&#…

opencv(c++)图像的灰度转换

opencv(c)图像的灰度转换 quickopencv.h #pragma once #include <opencv2/opencv.hpp> using namespace cv; class QuickDemo { public:void colorSpace_Demo(Mat& image); };quickopencv.cpp #include "quickopencv.h"// QuickDemo类中的颜色空间演示函…

problem forward和solution backward有什么区别

Note: 在具体研究中&#xff0c;problem forward是先提出问题&#xff0c;然后围绕着科学问题设计出完美的解决方案&#xff1b;而solution backward是先盘算自己有哪些技术&#xff0c;有哪些解决方案&#xff0c;反过来去寻找和定义问题。

C++构造函数详解

构造函数详解&#xff1a;C 中对象初始化与构造函数的使用 在 C 中&#xff0c;构造函数是一种特殊的成员函数&#xff0c;它在创建对象时自动调用&#xff0c;用来初始化对象的状态。构造函数帮助我们确保每个对象在被创建时就处于一个有效的状态&#xff0c;并且在不传递任何…

使用WebSocket技术实现Web应用中的实时数据更新

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 使用WebSocket技术实现Web应用中的实时数据更新 使用WebSocket技术实现Web应用中的实时数据更新 使用WebSocket技术实现Web应用中…

[N1CTF 2018]eating_cms

打开题目 只有个登录框&#xff0c;其他什么都没有&#xff0c;尝试了一下弱口令&#xff0c;没能成功 尝试访问一下register.php&#xff0c;看看能不能注册个账号 注册页面&#xff0c;随便注册个账号登陆一下 url中感觉是个注入点&#xff0c;尝试使用file伪协议读取一下us…

算法之二分查找优化:leetcode34:在排序数组中查找元素的第一个和最后一个位置

题干 分析 问题背景 给定一个已排序的数组&#xff0c;目标是找到一个给定的目标值 target 在数组中的 第一个位置 和 最后一个位置。如果目标值不存在&#xff0c;返回 [-1, -1]。 由于题干要求的时间复杂度是 O(log n)&#xff0c;并且数组是有序的&#xff0c;考虑使用二分…