【C++初阶】之类和对象(中)

【C++初阶】之类和对象(中)

  • ✍ 类的六个默认成员函数
  • ✍ 构造函数
    • 🏄 为什么需要构造函数
    • 🏄 默认构造函数
    • 🏄 为什么编译器能自动调用默认构造函数
    • 🏄 自己写的构造函数
    • 🏄 构造函数的特性
  • ✍ 拷贝构造函数
    • 🏄 编译器默认生成的拷贝构造函数
    • 🏄 自己写的拷贝构造函数
    • 🏄 拷贝构造函数调用的场景
  • ✍ 赋值运算符重载(也叫拷贝赋值函数)
    • 🏄 运算符重载的引入
      • 💘 前置++和后置++重载
      • 💘 运算符重载函数的调用
    • 🏄 赋值运算符重载
      • 💘 编译器默认生成的赋值运算符重载函数
      • 💘 自己显示写的赋值运算符重载函数
  • ✍ 析构函数
    • 🏄 编译器默认生成的析构函数
    • 🏄 显式写的析构函数
    • 🏄 析构函数的特性
    • 🏄 没有深拷贝,导致二次释放同一空间问题
      • 💘 问题的引入---拷贝构造函数
      • 💘 问题的解决---深拷贝
      • 💘 赋值运算符重载函数的浅拷贝问题
  • ✍ const成员函数
    • 🏄 const对象访问的规则
    • 🏄 非const对象访问的规则
  • ✍ 对普通对象的取地址运算符重载和对const对象取地址运算符重载
  • ✍ C++默认构造函数提供的机制
    • 🏄 C++默认构造函数是否提供的情况

📃博客主页: 小镇敲码人
💞热门专栏:C++初阶
🚀 欢迎关注:👍点赞 👂🏽留言 😍收藏
🌏 任尔江湖满血骨,我自踏雪寻梅香。 万千浮云遮碧月,独傲天下百坚强。 男儿应有龙腾志,盖世一意转洪荒。 莫使此生无痕度,终归人间一捧黄。🍎🍎🍎
❤️ 什么?你问我答案,少年你看,下一个十年又来了 💞 💞 💞

✍ 类的六个默认成员函数

当类为空是编译器也不是什么都不生成,而是会生成六大默认成员函数。

在这里插入图片描述
我们也可以自己显式把这六个默认成员写出来,这样编译器就会调用我们自己的,而不会调用默认生成的。

✍ 构造函数

🏄 为什么需要构造函数

我们学习C语言的时候,初始化栈操作需要自己写一个Init函数,但是这样就很麻烦,因为初始化栈之后需要我们显示的去调用Init函数,否则就有可能出现野指针的情况,因为如果是链式的栈,要把next指针初始化为空。

🏄 默认构造函数

我们构造函数就是为了解决这样的问题,在初始化类的时候,
你不需要显示的调用Init函数,编译器会自动的去调用,如果你不去显示的写,

编译器会生成一个默认的构造函数。我们来验证一下。
class Date
{
private:
 int year;
 int day;
 int month;
};
int main()
{
 Date x;
 return 0;
}

此时我们写了一个Date类,编译器会给调用它的默认构造函数吗?运行结果:

在这里插入图片描述

怎么回事呢?x对象的值没有被初始化呀,那是不是代表编译器没有调用默认构造函数呢?其实不然,C++把类型分为自定义类型和内置类型,默认构造函数要做的是,自定义类型去调用它自己的构造函数(如果有的话),内置类型去给一个随机值,那到底是不是这样呢?我们也可以来验证一下。

class year
{
public:
	year()
	{
		std::cout << "year()" << std::endl;
	}
};
class Date
{
private:
	year y;
	int day;
	int month;
};
int main()
{
	Date x;
	return 0;
}

注意:那个自定义类型的构造函数必须是public的,否则在它自己的类外面就访问不了。

在这里插入图片描述
运行结果:

在这里插入图片描述

默认构造函数默认成员函数是两个不同的概念,两者不能混淆,不用我们传参数,全缺省构造函数和无参数构造函数、默认生成的构造函数都称作为默认构造函数。

class Date
{
public:
	Date()
	{
		day = 0;
		month = 0;
	}
	Date(int day = 0,int month = 0)
	{

	}
private:
	year y;
	int day;
	int month;
};
int main()
{
	Date x;
	return 0;
}

注意:上面那两个默认构造函数不能同时存在,因为都不需要传参数,会造成歧义,编译器不知道调用哪一个默认构造函数。

在这里插入图片描述

🏄 为什么编译器能自动调用默认构造函数

那为什么编译器能在实例化类对象的的时候自动调用它的构造函数呢?

可以认为这是编译器做了特殊的处理,它帮助我们调用了这个函数。我们转到反汇编,可以发现编译器帮助我们调用了。

在这里插入图片描述

🏄 自己写的构造函数

我们也可以自己显示的写构造函数,那样编译器就不会去调用默认生成的构造函数了。


class year
{
public:
	year()
	{
		std::cout << "year()" << std::endl;
	}
};
class Date
{
public:
	Date()
	{
		day = 0;
		month = 0;
	}
private:
	year y;
	int day;
	int month;
};
int main()
{
	Date x;
	return 0;
}

运行结果:

在这里插入图片描述

可以看到,编译器在我们自己写的构造函数进去前,仍然会先去调用自定义类型的构造函数。

🏄 构造函数的特性

1、一次实例化对象只会调用一次,不支持显示调用。

在这里插入图片描述

2、构造函数会在实例化对象的时候自动调用,只用于初始化对象的一些成员变量,是初始化对象,而不是给对象开空间。

3、函数名和类名相同,无返回值。

4、支持重载。

✍ 拷贝构造函数

拷贝构造函数是构造函数的一种,主要作用是实现用一个已经存在的类对象,去初始化创建另外一个类对象。

🏄 编译器默认生成的拷贝构造函数

和前面普通的构造函数一样,如果我们不写编译器就会默认生成。

class year
{
public:
	year()
	{
		std::cout << "year()" << std::endl;
	}
};
class Date
{
public:
	Date()
	{
		day++;
		month++;
	}
	void f()
	{

	}
private:
	year y;
	int day = 0;
	int month = 0;
};
int main()
{
	Date x;
	Date y(x);
	return 0;
}

运行结果:

在这里插入图片描述

那我们为什么要写呢?这样岂不是浪费时间多次一举吗,编译器都帮助我们写好了,我们有时候的确是不需要写的,比如在没有向堆申请空间的时候,这时不涉及资源的清理,浅拷贝不会出问题,但是一旦我们向堆上申请空间后,不自己写深拷贝的拷贝构造函数,就会造成二次释放相同空间的问题。

🏄 自己写的拷贝构造函数

Date(const Date& x)
{
    day = x.day;
	month = x.month;
	y = x.y;
}

这里加上const是因为我们只是用x去初始化,但不希望改变它的值,至于这里为什么要使用引用,而且必须使用引用否则就会引发无穷递归:

在这里插入图片描述

这是因为我们在传参的时候,实参和形参的关系是,形参是实参的拷贝(当两者类型一样时),这不就相当于使用实参去初始化形参吗(也就是一个类去初始化另外一个类),也要调用拷贝构造函数,下一次又是一样的情况,所以会造成无穷递归,但是加了引用,你这个形参就是我实参的别名,不用再去调用拷贝构造,也就不会出现这种问题。

🏄 拷贝构造函数调用的场景

刚刚我们其实已经说了两个场景了。

1、用一个创建好的类初始化另外一个没有初始化的类
2、函数传参(参数为自定义类型)
3、函数返回值(参数为自定义类型),2和3都不能带引用,否则就不会调用拷贝构造函数。
4、赋值运算符重载时,被赋值的类还没有创建。

✍ 赋值运算符重载(也叫拷贝赋值函数)

我们的内置类型可以支持,一个变量赋值给另外一个对象,比如:a = b(都是int类型),那我们类(自定义类型)支持吗,答案是肯定的,使用运算符重载就可以解决这个问题。

🏄 运算符重载的引入

在C++中,增加了运算符的重载,这是因为有时候自定义类型也需要做一些类似操作符的操作,引入运算符重载,极大的提升了代码的可读性,它的规则如下:

  1. 函数名为operator后面接需要重载的运算符,注意:不能重载一些莫名奇妙的符号像@。
  2. 函数原型:返回值类型 operator操作符(参数列表)

注意:运算符重载时必须要有一个自定义类型的参数,因为运算符重载就是为类而生的,如果你没有类参数,那就没有意义了。

在这里插入图片描述
编译器为了防止你乱搞,会报错的。上面是全局的运算符重载函数。

有时候有的运算符需要两个参数,但是我们在类里面设计的时候只有一个参数,实际上是有两个参数的,第一个参数传的是this指针,编译器给隐藏了

💘 前置++和后置++重载

我们来介绍一下两个特殊的运算符重载,前置++和后置++重载,这两个操作符名字都一样,该如何区分呢?

这里没有办法了,C++对其做了特殊的处理,即给后置++多传一个参数来去区分,并且++操作符重载,最多额外传一个int参数作区分,也是为了防止用户乱搞。

我们来实现一下Date类的前置++和后置++:

// 前置++运算符  
// 该运算符将对象的年份、月份和日期都递增1,并返回递增后的对象的引用  
Date& operator++() // 前置++  
{  
    year++;       // 递增年份  
    day++;        // 递增日期  
    month++;      // 递增月份  
    return *this; // 返回当前对象的引用  
}  

Date operator++(int) // 后置++  
{  
    Date tmp(*this); // 创建当前对象的副本  
    ++(*this);       // 递增当前对象(使用前置++)  
    return tmp;      // 返回递增前的对象的副本  
}

这里实际上我们在++日期的时候要考虑月份和年份的变化,这里我们主要是学习语法就不考虑了。
注意后置++的返回值不能带引用。因为我们返回的是副本,但是副本是临时对象(出了作用域销毁了),所以我们需要返回一个副本的拷贝,而不是副本本身。

  • 注意这里即使我们运算符重载函数写成全局的,也能像内置类型那样调用:
using namespace std;
class Date
{
public:
	Date(int year, int month = 2, int day = 1) ://普通的构造函数
		year_(year),
		month_(month),
		day_(day)
	{
		cout << "Date(int year, int month = 2, int day = 1)" << endl;
	}

	Date(const Date& x) ://拷贝构造函数
		year_(x.year_),
		month_(x.month_),
		day_(x.day_)
	{
		cout << "Date(const Date& x)" << endl;
	}

	Date& operator=(const Date& x)//拷贝赋值函数
	{
		year_ = x.year_;
		month_ = x.month_;
		day_ = x.day_;
		cout << "operator=(const Date& x)" << endl;
		return *this;
	}

	~Date()//析构函数
	{
		cout << "~Date" << endl;
	}
public:
	int year_;
	int month_;
	int day_;
};

// 前置++运算符  
// 该运算符将对象的年份、月份和日期都递增1,并返回递增后的对象的引用  
Date& operator++(Date& x) // 前置++  
{
	x.year_++;       // 递增年份  
	x.day_++;        // 递增日期  
	x.month_++;      // 递增月份  
	return x; // 返回当前对象的引用  
}

Date operator++(Date&x,int) // 后置++  
{
	Date tmp(x); // 创建当前对象的副本  
	++x;       // 递增当前对象(使用前置++)  
	return tmp;      // 返回递增前的对象的副本  
}

int main()
{
	Date x(2022);
	x++;
	++x;
}

运行结果:

在这里插入图片描述
代码正常运行。

如果我们给++运算符重载函数增加其它类型的参数,编译器就会报错:

在这里插入图片描述

💘 运算符重载函数的调用

内置类型可以直接a = b,或者a++,那我们的自定义类型是否可以这样了,为了可读性和方便,我们的C++支持这样来调用运算符重载函数,我们拿刚刚的前置++、和后置++函数来演示。

int main()
{
	Date x;
	x++;//-->operator++(&x,1);
	++x;//-->operator++(&x);
	return 0;
}

我们转到反汇编可以发现,确实是调用了对应的函数。

在这里插入图片描述
也可以显示调用,注意这里编译器已经帮助我们传了this指针过去,所以这里我们显示调用的是后置++:

在这里插入图片描述

🏄 赋值运算符重载

回归正题,我们继续来看我们的赋值运算符重载函数。

💘 编译器默认生成的赋值运算符重载函数

当我们不去显示的写赋值运算符重载函数,编译器会默认生成一个。

在这里插入图片描述

但是当我们这样去写,被赋值的y还没有被创建这个时候编译器就会去调用拷贝构造函数,无论你有没有自己显式的写

在这里插入图片描述

💘 自己显示写的赋值运算符重载函数

下面我们来自己显示的写一下,还是会有深拷贝的问题,当我们类的成员变量有在堆上申请空间时,直接赋值会引发二次析构的问题。

// 赋值运算符重载函数  
// 将参数x的值赋给当前对象,并返回当前对象的引用  
Date& operator=(const Date& x)  
{  
    if (this != &x) // 检查自赋值  
    {  
        day = x.day;  
        month = x.month;  
        year = x.year;  
    }  
    return *this;  
}

现代写法:

这种写法在拷贝构造函数处理好深拷贝问题后,可以很好的实现深拷贝,因为我们这种写法本质是对拷贝构造函数的一个复用。

Date& operator=(const Date& x)  
{  
	// 检查自赋值,避免不必要的操作  
	if (this != &x)  
	{  
		// 创建一个临时Date对象tmp,并使用参数x来初始化它  
		Date tmp(x);  
  
		// 使用std::swap来交换tmp对象的day成员和当前对象的day成员  
		std::swap(tmp.day, this->day);  
  
		// 使用std::swap来交换tmp对象的year成员和当前对象的year成员  
		std::swap(tmp.year, this->year);  
  
		// 使用std::swap来交换tmp对象的month成员和当前对象的month成员  
		std::swap(tmp.month, this->month);  
  
		// 通过上述交换,实际上是将tmp对象(即x的副本)的内容赋给了当前对象  
	}  
  
	// 返回当前对象的引用,以支持链式赋值操作  
	return *this;  
}

在这里插入图片描述

运行结果:

在这里插入图片描述

✍ 析构函数

有初始化资源的函数,就会有清理资源的函数。析构函数和构造函数一样,它是在当前作用域结束后就会自动调用析构函数。它的函数名字不一样,类名前面多了一个~

🏄 编译器默认生成的析构函数

一般情况下编译器也会默认生成一个析构函数,当我们的成员变量都没有申请资源时就不需要显示的写析构函数。

🏄 显式写的析构函数

	~Date()
	{
		year = 0;
		day = 0;
		month = 0;
	}

在这里插入图片描述

🏄 析构函数的特性

1、当前函数作用域结束后自动调用
2、无参数,无返回值
3、函数名是~+类名。
4、功能是清理对象中的资源而不是释放对象的空间。
5、支持显示调用,构造函数不支持。

在这里插入图片描述

🏄 没有深拷贝,导致二次释放同一空间问题

💘 问题的引入—拷贝构造函数

前面在讲拷贝构造函数和赋值构造函数,我们就对这个问题做了铺垫,这个问题的本质就和标题一样,内存重复释放,为什么会这样,本质还是万恶的值拷贝!下面我们写一段代码来解释并解决这个问题。

class Stack
{
public:
	Stack()
	{
		_capacity = 4;//假设开始的时候给容量设置为4
		_top = 0;
		_a = (int*)malloc(sizeof(int) * _capacity);
		if (_a == nullptr)
		{
			std::cout << "malloc Failed" << std::endl;
			exit(-1);
		}
	}
	~Stack()
	{
		std::cout << " ~Stack" << std::endl;
		_capacity = 0;
		_top = 0;
		free(_a);
		_a = nullptr;
	}
private:
	int* _a;
	int _top;		// 栈顶
	int _capacity;  // 容量 
};

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

运行结果:

在这里插入图片描述

是的,程序在这里崩溃了,我们来调试一下。

在这里插入图片描述

可以看到st1中的_a、和st2中的_a保存的地址值是一模一样,释放了两次相同空间的地址。

在这里插入图片描述

💘 问题的解决—深拷贝

那么我们如何规避这种情况呢,就要用到深拷贝,我们可以开和st1中_a指向空间一样大小的数组,并把_a指向空间的值赋值给我们的数组。

在这里插入图片描述
代码实现:

// Stack类的拷贝构造函数  
// 接收一个对Stack类型的常量引用st作为参数,用于复制对象  
Stack(const Stack& st)  
{  
    // 为栈的底层数组_a分配内存,大小与源栈st的容量相同  
    _a = (int*)malloc(sizeof(int) * (st._capacity));  
  
    // 检查内存是否分配成功  
    if (_a == nullptr)  
    {  
        // 如果分配失败,则输出错误信息并退出程序  
        std::cout << "内存分配失败" << std::endl;  
        exit(-1);  
    }  
  
    // 使用memcpy函数将源栈st的底层数组内容复制到当前栈的底层数组_a中  
    memcpy(_a, st._a, sizeof(int) * (st._capacity));  
  
    // 复制源栈st的栈顶指针_top到当前栈  
    _top = st._top;  
  
    // 复制源栈st的容量_capacity到当前栈  
    _capacity = st._capacity;  
}

运行结果:

在这里插入图片描述

此时不再报错。

调试结果:

在这里插入图片描述
保存的地址不同(指向的空间不同),但是数组中的值相同,完成了拷贝构造(深拷贝)。

💘 赋值运算符重载函数的浅拷贝问题

使用编译器默认的值拷贝,去赋值,在刚刚的场景也会报错。

int main()
{
	Stack st1;
	Stack st2;
	st2 = st1;
	return 0;
}

在这里插入图片描述

我们可以使用赋值运算符重载函数现代写法来复用刚刚拷贝构造函数写好的深拷贝。

// Stack类的赋值运算符重载  
// 接收一个对Stack类型的常量引用st作为参数,用于赋值操作  
Stack& operator=(const Stack& st)  
{  
    // 检查是否自赋值,即当前对象与参数对象是否为同一个对象  
    if (this != &st)  
    {  
        free(_a);//释放之前_a的内存
        // 创建一个临时Stack对象tmp,并用参数对象st初始化  
        Stack tmp(st);  
  
        // 使用std::swap交换临时对象tmp的底层数组与当前对象的底层数组  
        std::swap(tmp._a, _a);  
  
        // 使用std::swap交换临时对象tmp的栈顶指针与当前对象的栈顶指针  
        std::swap(tmp._top, _top);  
  
        // 使用std::swap交换临时对象tmp的容量与当前对象的容量  
        std::swap(tmp._capacity, _capacity);  
    }  
  
    // 返回当前对象的引用,支持链式赋值操作  
    return *this;  
}

运行结果:

在这里插入图片描述

调试结果:

在这里插入图片描述
与预期一致。

✍ const成员函数

使用const关键字修饰的函数(放在函数括号右边)叫做const成员函数,const实际是修饰的this指针指向的内容,所以其指向的内容不能修改。

请看下面的代码:

class Date
{
public:
	Date()
	{
		year = 2024;
		month = 1;
		day = 1;
	}
	void f() const
	{
		this->year = 1;
	}
private:
	int year;
	int month;
	int day;
};

int main()
{
	Date x;
}

在这里插入图片描述

🏄 const对象访问的规则

1、const对象不能访问非const类型的函数,但是可以构造函数和析构函数例外。这很好理解,因为我们的const修饰对象,对象的内容不能被修改,如果你能调用非const函数,在这个函数里修改了我们的成员变量,那不就逻辑不自洽了嘛。

在这里插入图片描述
const对象访问构造函数。

也不能对析构或者构造函数使用const修饰。

在这里插入图片描述

const对象访问析构函数。

在这里插入图片描述

const对象访问非const函数是非法的。

在这里插入图片描述

2、const成员函数类也不能调用其它的非const的成员函数。

在这里插入图片描述

本质上是一样的问题const Date* const this类型不能转变为Date* const this,否则它的能力就扩大了。

  • 注意前面的const修饰的是*this,表示this指向的内容具有常性,后面的const修饰this指针,表示this指针的值不能被修改。

🏄 非const对象访问的规则

3、但是非const成员函数内可以调用const成员函数。

在这里插入图片描述
程序正常退出。

4、非const对象也可以调用const函数。

在这里插入图片描述

3和4总结起来也是一样的,Date* const this类型可以向const Date* const this类型转化。

✍ 对普通对象的取地址运算符重载和对const对象取地址运算符重载

这两个函数一般都不需要我们显示的去写,编译器会默认生成的。

在这里插入图片描述

我们也可以显示的写出来。

// 非const成员函数的取地址运算符重载  
// 返回当前对象的地址  
Date* operator&()  
{  
    return this;  
}

// const成员函数的取地址运算符重载  
// 返回当前对象的const地址  
const Date* operator&() const  
{  
    return this;  
}

但是通常只有我们有一些特殊的需求比如取出某个特定成员变量的地址时,才需要自己显示的去写。

✍ C++默认构造函数提供的机制

部分内容参考博主这篇博客C++默认构造函数提供的机制。

我们都知道,在C++98中,有着这样的几种构造函数:普通构造函数、析构函数、拷贝构造函数、赋值运算符重载函数。

生成这些特殊的成员函数(或者不生成)的规则比较复杂,编译器默认生成的构造函数是有可能被删除的。

🏄 C++默认构造函数是否提供的情况

  1. 如果自定义了普通构造函数和拷贝构造函数,系统将不再提供默认的无参构造函数。

在这里插入图片描述
但是如果定义了一个赋值运算符重载函数,系统还是会提供普通的无参构造函数。

在这里插入图片描述

2、如果自定义了一个普通的构造函数,系统还会提供一个拷贝构造函数和赋值运算符重载函数(值拷贝)。

  1. 如果自定义了一个拷贝构造函数,系统将不再提供默认的拷贝构造函数。但是会生成默认的赋值运算符重载函数。

在这里插入图片描述
4、如果自定义了一个赋值运算符重载函数,系统就不会默认生成赋值运算符重载函数了,但是其它函数还是会生成。

在这里插入图片描述
在这里插入图片描述
这里少打字了,应该是无参的构造函数。

没有生成报错是这样的:

在这里插入图片描述

  1. 如果自定义了一个析构函数,系统也就不会再提供默认的析构函数。

  2. 如果类里面有没有初始化的非静态const数据成员或者引用类型的数据成员,会导致默认提供的默认构造函数被删除。

在这里插入图片描述
当我们使用初始化列表初始化好这两个变量好,发现去调用拷贝构造函数是可以的(编译器默认生成了),但是拷贝赋值函数却被删除了。

在这里插入图片描述
在这里插入图片描述

6.用户如果自己没有提供一个拷贝构造函数或者拷贝赋值函数,编译器会隐式声明一个。

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

原型链-(前端面试 2024 版)

来讲一讲原型链 原型链只存在于函数之中 四个规则 1、引用类型&#xff0c;都具有对象特性&#xff0c;即可自由扩展属性。 2、引用类型&#xff0c;都有一个隐式原型 __proto__ 属性&#xff0c;属性值是一个普通的对象。 3、引用类型&#xff0c;隐式原型 __proto__ 的属…

Java官网64位下载:获取高效、安全的Java平台

Java官网64位下载&#xff1a;获取高效、安全的Java平台 Java是一种广泛应用于软件开发和跨平台应用程序的编程语言。无论是开发桌面应用程序、移动应用程序还是大型企业级系统&#xff0c;Java都是一种可靠且强大的选择。为了确保你获取到高效、安全的Java平台&#xff0c;本文…

supervision CV视觉可视化辅助工具

参考&#xff1a; https://supervision.roboflow.com/latest/ https://github.com/roboflow/supervision/tree/develop/examples 版本&#xff1a; pip install -U supervisionultralytics-8.1.35 &#xff08;大于8.1才行&#xff0c;不然可能会有错误AttributeError: ‘Res…

第5章.零、单例与小样本提示词的编写之道

零提示、单个提示和小样本提示是用于从ChatGPT中生成文本的技术。在数据匮乏或任务全新、定义模糊之时&#xff0c;我们用微妙的提示&#xff0c;让ChatGPT从无到有&#xff0c;生成文本。 面对任务&#xff0c;空无一例&#xff1a;模型凭借对任务的广泛理解&#xff0c;独辟…

贝锐蒲公英虚拟DMZ:工业设备异地组网,解决网段冲突难题

虚拟DMZ 产品/技术的原理传统DMZ&#xff1a; DMZ中文名称为“隔离区”&#xff0c;也称“非军事化区”&#xff1b;它是为解决安装防火墙后外部网络不能访问内部网络服务器的问题。网关DMZ功能开启后&#xff0c; 将内网的一台服务器完全暴露在外网&#xff08;内网某个IP绑…

在CentOS7上部署Nginx并测试指南

Nginx部署测试 Nginx简介 Nginx是俄罗斯人Igor Sysoev编写的一款高性能的HTTP和反向代理服务器。 Nginx选择了epoll和kqueue作为网络I/O模型&#xff0c;在高连接并发的情况下&#xff0c;内存、CPU等系统资源消耗非常低&#xff0c;运行稳定。 正向代理与反向代理 正向代…

Swift 周报 第四十八期

文章目录 前言新闻和社区苹果突然不造车了&#xff0c;雷军&#xff1a;非常震惊&#xff01;分析师&#xff1a;马斯克或是最大赢家你会爱上的开发者活动 提案通过的提案正在审查的提案 Swift论坛推荐博文话题讨论关于我们 前言 本期是 Swift 编辑组自主整理周报的第四十八期…

【MySQL】16.事务管理(重点) -- 2

1. 事务隔离级别 如何理解隔离性1 MySQL服务可能会同时被多个客户端进程(线程)访问&#xff0c;访问的方式以事务方式进行一个事务可能由多条SQL构成&#xff0c;也就意味着&#xff0c;任何一个事务&#xff0c;都有执行前&#xff0c;执行中&#xff0c;执行后的阶段。而所…

基于Echarts的超市销售可视化分析系统(数据+程序+论文)

本论文旨在研究Python技术和ECharts可视化技术在超市销售数据分析系统中的应用。本系统通过对超市销售数据进行分析和可视化展示&#xff0c;帮助决策层更好地了解销售情况和趋势&#xff0c;进而做出更有针对性的决策。本系统主要包括数据处理、数据可视化和系统测试三个模块。…

基于随机森林与LSTM神经网络的住宅用电比较分析及预测 代码+论文 完整毕设

摘要 本文旨在探讨基于随机森林&#xff08;Random Forest&#xff09;与长短期记忆神经网络&#xff08;Long Short-Term Memory, LSTM&#xff09;的住宅用电比较分析及预测方法。随机森林是一种集成学习方法&#xff0c;通过构建多个决策树进行预测&#xff0c;具有较强的鲁…

FL Studio21.2.3.4004音乐制作及里程碑及功能介绍

**FL Studio 21.2.3.4004&#xff1a;音乐制作的新里程碑** 随着数字音乐制作技术的不断发展&#xff0c;音乐制作软件也在不断迭代升级。今天&#xff0c;我们将聚焦于一款广受欢迎的音乐制作软件——FL Studio 21.2.3.4004&#xff0c;探讨它如何成为音乐制作领域的新里程碑…

【技巧】如何设置和解除PDF的“打开密码”?

在工作中&#xff0c;我们经常会接触到PDF文件&#xff0c;对于重要的文件&#xff0c;往往还会设置密码保护&#xff0c;那PDF的“打开密码”如何设置和解除呢&#xff1f;下面小编分享两种方法&#xff0c;一起来看看吧&#xff01; 方法一&#xff1a;使用PDF编辑器 大部分…

基于连续深度编解码器网络的医学图像鲁棒边界分割

基于连续深度编解码器网络的医学图像鲁棒边界分割 摘要引言相关工作方法-----III. PROPOSED METHOD Robust_Boundary_Segmentation_in_Medical_Images_Using_a_Consecutive_Deep_Encoder-Decoder_Network 摘要 图像分割通常用于定位目标和边界。它在许多临床应用中是必不可少的…

一步一步搭建,功能最全的权限管理系统之动态路由菜单

一、前言 这是一篇搭建权限管理系统的系列文章。 随着网络的发展&#xff0c;信息安全对应任何企业来说都越发的重要&#xff0c;而本系列文章将和大家一起一步一步搭建一个全新的权限管理系统。 说明&#xff1a;由于搭建一个全新的项目过于繁琐&#xff0c;所有作者将挑选核心…

1320亿参数,性能超LLaMA2、Grok-1!开源大模型DBRX

3月28日&#xff0c;著名数据和AI平台Databricks在官网正式开源大模型——DBRX。 DBRX是一个专家混合模型&#xff08;MoE&#xff09;有1320亿参数&#xff0c;能生成文本/代码、数学推理等&#xff0c;有基础和微调两种模型。 根据DBRX在MMLU、HumanEval和 GSM8K公布的测试…

蓝牙双模音频模块支持串口AT指令控制介绍

目录 一、BT401蓝牙音频模块简介 蓝牙音频模块支持串口AT指令控制介绍&#xff0c;这里推荐BT401蓝牙模块&#xff0c;功能简介如下&#xff1a; BT401模块是一款支持蓝牙、U盘、TF卡播放的5合1的解决方案。模组的亮点在支持无损音乐的播放&#xff0c;以及简单明了的串口控制…

婴儿专用洗衣机哪个牌子好?四大爆款婴儿洗衣机合集安利

婴儿的衣物需要特别的护理&#xff0c;因为婴儿的皮肤非常娇嫩&#xff0c;需要一个无菌&#xff0c;没有刺激性的洗涤环境&#xff0c;于是婴儿洗衣机应运而生。如果你非常注重婴儿衣物的卫生问题&#xff0c;那么婴儿洗衣机则是非常理想的选择。毕竟&#xff0c;在婴儿吃奶或…

文件上传失败原因分析与解决

图片文件上传失败 问题描述&#xff1a;在前端开发时&#xff0c;需要通过表单元素上传图片或其他文本&#xff0c;但是上传不成功&#xff0c;后端接口也没问题 html <!--onChange用来绑定数据 handleUpload用来提交数据--><form onSubmit{handleUpload}><…

Cadence HDL导出BOM并将网页数据导入Excle

【仅供个人学习记录&#xff0c;勿作他用。转载注明出处】 1. 如何导出BOM&#xff1f; 【说明】将后缀改为网页“html”&#xff0c;并勾选下面的网页。 之后就会跳出浏览器中你的BOM表就会显示。 2. 将网页BOM导入Excle&#xff1f; 不想要这个 想要这个&#xff01;&…

vscode配置c/c++调试环境

本文记录win平台使用vscode远程连接ubuntu server服务器下&#xff0c;如何配置c/c调试环境。 过程 1. 服务器配置编译环境 这里的前置条件是vscode已经能够连接到服务器&#xff0c;第一步安装编译构建套件&#xff08;gcc、g、make、链接器等&#xff09;和调试器&#xf…