【 C++ 】 类和对象的学习 (二)

news2024/9/24 13:21:42

😘我的主页:OMGmyhair-CSDN博客

目录

I、类的默认成员函数

一、构造函数

二、析构函数

三、拷贝构造函数

四、

运算符重载

赋值运算符重载

五、取地址重载_普通对象

六、取地址重载_const对象



I、类的默认成员函数

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

接下来我们将介绍以下6个默认成员函数:

这篇文章将重点介绍前四个,稍微了解后两个,在C++11中还增加了两个默认成员函数——移动构造和移动赋值。


一、构造函数

构造函数的主要功能是对对象实例化时进行初始化,注意不是创建对象,局部对象是在栈帧创建时就一并开好了空间完成了创建的。

构造函数有以下几个点需要注意:

1. 函数名与类名相同。

2. 无返回值。

3. 对象实例化时系统会⾃动调⽤对应的构造函数。

4. 构造函数可以重载。

5. 如果类中没有显式定义构造函数,则C++编译器会⾃动⽣成⼀个⽆参的默认构造函数,⼀旦⽤⼾显 式定义编译器将不再⽣成。

6. ⽆参构造函数、全缺省构造函数、我们不写构造时编译器默认生成的构造函数,都叫做默认构造函 数。但是这三个函数有且只有⼀个存在,不能同时存在。⽆参构造函数和全缺省构造函数虽然构成 函数重载,但是调用时会存在歧义。没有参数就可以调用的构造就叫默认构造。

class Person
{
public:
	Person()//无参
	{
		cout << "初始化,无参" << endl;
		_age = 0;
		_height = 50;
		_weight = 20;
	}

	Person(int age=0)//全缺省
	{
		cout << "初始化,全缺省" << endl;
		_age = age;
		_height = 50;
		_weight = 20;
	}
	int _age;
	int _height;
	int _weight;
};

int main()
{
	Person pete;
	return 0;
}

此时调用产生歧义,编译器报错:

在调用默认构造函数时,不要加(),编译器会认为是函数声明,而函数中可以放函数声明,不会报错。

7. 我们不写,编译器默认⽣成的构造,对内置类型(例如int,char,double...)成员变量的初始化是不确定的,取决于编译器。对于自定义类型(自己定义的class/struct类型)成员变量,要求调用这个成员变量的默认构造函数初始化。如果这个成员变量,没有默认构造函数,那么就会报错。

class Person
{
public:
	Person()
	{
		cout << "create person!" << endl;
		age = 0;
		height = 50;
		weight = 10;
	}
	int age;
	int height;
	int weight;
};

class Family
{
public:
	Family()
	{
		cout << "create family!" << endl;
		num = 1;
	}
	Person pete;
	int num;
};

int main()
{
	Family one;
	cout << one.pete.height << endl;//输出50
	return 0;
}

在最后,程序输出了50,证明会调用自定义类型Person的默认构造函数对成员变量pete进行初始化。

因此当类中的成员变量全都是自定义类型,我们可以使用自动生成的默认构造。当类中成员变量有内置类型时或者需要显示传参初始化,就自己写构造函数。

在C++11中,我们还可以不用默认构造函数对内置类型进行初始化:

class Person
{
public:
	
	int _age = 0;
	int _height = 0;
	int _weight = 0;
};

int main()
{
	Person pete;
	return 0;
}

二、析构函数

如同构造函数,析构函数也不是对对象进行销毁,对象的销毁是在函数结束栈帧销毁。C++规定对象在销毁时会自动调用析构函数,而析构函数的作用类似于对申请的资源进行释放。这样可以有效避免内存泄漏问题,我们因为忘记释放而造成内存泄漏,因为在析构函数是自动调用的。

析构函数的特点如下:

1.析构函数的函数名是在类名前加上~

2.没有参数没有返回值

3.一个类中只能有一个析构函数。没有显示写明,则编译器会自动生成一个默认的析构函数

4.当对象生命周期结束,系统会自动调用析构函数

5.系统自动生成的析构函数不会处理内置类型成员(int char double),对于自定义的类型成员会调用它们的析构函数。

6.即使你写明的析构函数中没有处理自定义的类型成员,编译器还是会调用这些成员自己的析构函数。即无论在什么情况下,自定义类型成员都会调用它们自己的析构函数。

7.当申请了资源时,一定要自己写析构函数。如果没申请,可以不用写。

8.先定义的对象后销毁,我们可以将这个用栈来理解,它们也遵循先进后出的规则。

我们简单写一个类,来看看析构函数:

class Room
{
public:
	Room(int _height=1,int _area=1)
	{
		cout << "Room构造函数" << endl;
		_room = (int*)malloc(sizeof(int) * _height * _area);
	}

	~Room()
	{
		cout << "Room析构函数" << endl;
		free(_room);
		_room = nullptr;
	}

private:
	int* _room;
	int _height;
	int _area;
};

int main()
{
	Room r1;
	return 0;
}

看看运行结果:

可以看到编译器自动调用了构造函数以及析构函数。

在构造函数中,我们申请了资源,在析构函数中自动释放资源。

再来看看下面这种情况:

class House
{
public:
	House(int _price=1000,string _name="翻斗花园")
	{
		cout << "House构造函数" << endl;
	}

	~House()
	{
		cout << "House析构函数" << endl;
	}
private:
	Room _r;
	int _price;
	string _name;
};

int main()
{
	House h;
	return 0;
}

可以看到在House的析构函数中,我们没有对自定义Room类型的成员做任何处理,来看看运行结果:

可以看到系统自动调用了Room的析构函数,即使你在House析构函数中没有进行处理。

再来看看House的默认析构函数:

class Room
{
public:
	Room(int _height = 1, int _area = 1)
	{
		cout << "Room构造函数" << endl;
		_room = (int*)malloc(sizeof(int) * _height * _area);
	}

	~Room()
	{
		cout << "Room析构函数" << endl;
		free(_room);
		_room = nullptr;
	}

private:
	int* _room;
	int _height;
	int _area;
};

class House
{
public:
	House(int _price = 1000, string _name = "翻斗花园")
	{
		cout << "House构造函数" << endl;
	}
	//此时我们没有写明析构函数
private:
	Room _r;
	int _price;
	string _name;
};

int main()
{
	House h;
	return 0;
}

再来看看它的运行结果:

可以看到编译器默认生成的析构函数还是对自定义成员的析构函数进行了调用。

三、拷贝构造函数

当一个构造函数的第一个参数是自己类类型的引用,并且其它的参数都有默认值,那么这个构造函数叫做拷贝构造函数。

值得注意的是:C++规定传值传参调用拷贝构造

当我们想要用已存在的对象对别的对象进行初始化时,就可以使用拷贝构造函数:

class Date
{
public:
	Date(int year = 2024, int month = 9, int day = 3)
	{
		_year = year;
		_month = month;
		_day = day;
	}

	Date(const Date& date)
	{
		_year = date._year;
		_month = date._month;
		_day = date._day;
	}
	
	void Print()
	{
		cout << _year << " " << _month << " " << _day << endl;
	}

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

int main()
{
	Date d1(2024,1,1);
	Date d2(d1);
	d2.Print();
	return 0;
}

在c++中,d2(d1)还可以写成st2=st1这种形式:

int main()
{
	Date d1(2024,1,1);
	//Date d2(d1);
	Date d2 = d1;
	d2.Print();
	return 0;
}

运行结果如下:


需要注意的是:拷贝构造函数必须的第一个参数必须写成引用的形式,不能使用传参,会造成死循环。

错误写法:

为什么会造成死循环呢?

这时因为如果使用传值的形式,每次调用拷贝构造函数都会先进行传值传参,而C++规定传值传参调用拷贝构造,因此又会形成一个新的拷贝构造函数,从而造成死循环。

如下图所示:

为了避免这种情况,我们可以使用引用来进行对另外一个对象进行拷贝。为了防止在拷贝过程中,被引用对象被误修改,我们建议加上const。


我们有时会用到使用对象进行传值传参,这时也会自动调用拷贝构造函数,这时我们也可以使用引用的形式,这样省去了调用拷贝构造函数这一步:


既然拷贝构造函数也算是默认成员函数,那么当我们不主动去写时,编译器也会生成一个默认的拷贝构造函数。默认的拷贝构造函数会做些什么呢?

我们去掉我们写的拷贝构造函数试试看:

class Date
{
public:
	Date(int year = 2024, int month = 9, int day = 3)
	{
		_year = year;
		_month = month;
		_day = day;
	}

	/*Date(const Date& date)
	{
		_year = date._year;
		_month = date._month;
		_day = date._day;
	}*/

	void Print()
	{
		cout << _year << " " << _month << " " << _day << endl;
	}

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



int main()
{
	Date d1(2024, 1, 1);
	Date d2(d1);
	d2.Print();
	return 0;
}

看看运行结果:

可以看到依然完成了拷贝,如果是对自定义类型呢?

class SpecialDay
{
public:
	SpecialDay()
	{
		_date = 20240101;
	}
	SpecialDay(const SpecialDay& SDay)
	{
		cout << "SpecialDay的拷贝构造" << endl;
		_date = SDay._date;
	}

	int _date;
};

class Date
{
public:
	Date(int year = 2024, int month = 9, int day = 3)
	{
		_year = year;
		_month = month;
		_day = day;
		SDay._date=20240903;
	}

	/*Date(const Date& date)
	{
		_year = date._year;
		_month = date._month;
		_day = date._day;
	}*/

	void Print()
	{
		cout << _year << " " << _month << " " << _day << " " << SDay._date << endl;
	}

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



int main()
{
	Date d1(2024, 1, 1);
	Date d2(d1);
	d2.Print();
	return 0;
}

 运行结果:

可以看到调用了自定义类型成员自己的拷贝构造函数。


此时有一个问题,当我们传值返回的时候也会调用拷贝构造函数吗?

class Date
{
public:
	Date(int year = 2024, int month = 9, int day = 3)
	{
		_year = year;
		_month = month;
		_day = day;
		SDay._date=20240903;
	}

	Date(const Date& date)
	{
		_year = date._year;
		_month = date._month;
		_day = date._day;
		cout << "Date的拷贝构造函数" << endl;
	}


	void Print()
	{
		cout << _year << " " << _month << " " << _day << " " << SDay._date << endl;
	}

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

Date func(const Date& date)
{
	return date;
}

int main()
{
	Date d1(2024, 1, 1);
	/*Date d2(d1);
	d2.Print();*/
	func(d1);
	return 0;
}

在上面示例中,func函数进行了传值返回,是否会调用拷贝构造函数呢?

来看看运行结果:

可以看到它依然调用了拷贝构造函数,这是因为出了func函数体,date会赋值给一个临时对象,此时会调用拷贝构造函数。

此时我们可以使用传引用返回:

Date func(const Date& date)//传值返回,调用拷贝构造函数
{
	return date;
}

Date& func1(Date& date)//传引用返回,不调用
{
	return date;
}

但是传引用返回需要注意局部对象:

在下面这种情况中,temp是一个局部对象,出了函数体就被销毁,而此时返回的引用就类似于野指针了。

Date& func1(Date& date)
{
	Date temp;
	return temp;
}

综上所述,我们对拷贝构造函数的特点进行总结:

1.是构造函数的一个重载

2.第一个参数必须是类类型对象的引用

3.C++规定传值传参和传值返回调用拷贝构造函数

4.自动生成的拷贝构造函数会对内置类型成员变量完成值拷贝/浅拷贝,对于自定义类型成员变量会调用它们自己的拷贝构造函数。但是当我们申请了资源时,拷贝构造函数也需要自己写去进行深拷贝。


四、

运算符重载

当我想要对类的对象进行加减乘除等操作,可以直接使用运算符对对象进行操作吗?

不可以,但是C++中允许我们使用运算符重载的方式让运算符能用于对象的操作中。  *  就是一个典型的运算符重载,它能是乘号也能是解引用。

在这里我们定义一个日期类:

class Date
{
public:
	Date(int y=2024,int m=9,int d=2)
	{
		_year = y;
		_month = m;
		_day = d;
	}

	int _year;
	int _month;
	int _day;
};

当我们想要比较两个日期是否相等,应该怎么做?

class Date
{
public:
	Date(int y=2024,int m=9,int d=2)
	{
		_year = y;
		_month = m;
		_day = d;
	}

	int _year;
	int _month;
	int _day;
};

bool operator==(Date d1, Date d2)
{
	return d1._day == d2._day
		&& d1._month == d2._month
		&& d1._year == d2._year;
}

int main()
{
	Date date1(1949, 10, 1);
	Date date2(2024, 10, 1);
	if (operator==(date1, date2))
	{
		cout << "日期相等" << endl;
	}
	else
	{
		cout << "日期不相等" << endl;
	}
	return 0;
}

在C++中operator==(date1,date2)还可以写成date1==date2。

此时你可能注意到了一个问题,成员变量我们一般设为私有,但是私有不能在类外进行访问。

我们通常有三种方法进行解决。

1.将其设为公有(不推荐)

2.提供get函数

class Date
{
public:
	Date(int y=2024,int m=9,int d=2)
	{
		_year = y;
		_month = m;
		_day = d;
	}

	int GetY()
	{
		int year = _year;
		return year;
	}

	int GetM()
	{
		int month = _month;
		return month;
	}

	int GetD()
	{
		int day = _day;
		return day;
	}

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

bool operator==(Date d1, Date d2)
{
	return d1.GetD() == d2.GetD()
		&& d1.GetM() == d2.GetM()
		&& d1.GetY() == d2.GetY();
}

int main()
{
	Date date1(1949, 10, 1);
	Date date2(2024, 10, 1);
	/*if (operator==(date1, date2))
	{
		cout << "日期相等" << endl;
	}
	else
	{
		cout << "日期不相等" << endl;
	}*/

	if (date1==date2)
	{
		cout << "日期相等" << endl;
	}
	else
	{
		cout << "日期不相等" << endl;
	}
	return 0;
}

3.将重载函数变为成员函数

class Date
{
public:
	Date(int y = 2024, int m = 9, int d = 2)
	{
		_year = y;
		_month = m;
		_day = d;
	}

	bool operator==(Date d2)
	{
		return _year == d2._year
			&& _month == d2._month
			&& _day == d2._day;
	}

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


int main()
{
	Date date1(1949, 10, 1);
	Date date2(2024, 10, 1);
	/*if (operator==(date1, date2))
	{
		cout << "日期相等" << endl;
	}
	else
	{
		cout << "日期不相等" << endl;
	}*/

	/*if (date1 == date2)
	{
		cout << "日期相等" << endl;
	}
	else
	{
		cout << "日期不相等" << endl;
	}*/

	if (date1.operator==(date2))
	{
		cout << "日期相等" << endl;
	}
	else
	{
		cout << "日期不相等" << endl;
	}
	return 0;
}

赋值运算符重载

赋值运算符重载是一个默认成员函数,用于两个已经存在的对象直接的拷贝赋值。C++规定必须重载为成员函数。它和拷贝构造函数的区别在于,它是两个已经存在的对象之间,而拷贝构造函数是一个对象拷贝给另外一个初始化的对象。

Date& operator=(const Date& date)
{
	_year = date._year;
	_month = date._month;
	_day = date._day;
	return *this;
}

赋值运算符重载是有返回值的,this是调用对象的地址,返回对象是为了连续赋值这一场景。参数我们使用const,以防在赋值过程中误处理,参数使用&避免造成传值传参。

与拷贝构造函数类似,自动生成的赋值运算符重载会对内置类型进行值拷贝/浅拷贝,对于自定义类型则会调用它们自己的赋值运算符重载。


一般来说,默认生成的取地址重载函数已经足够用,除非特殊场景,比如你不希望别人通过&取得对象的地址。

五、取地址重载_普通对象

首先我们来看对普通对象进行取地址:

Date* operator&()
{
	return this;
}

很简单,我们只需要返回this就行,因为this就是调用对象的地址。


六、取地址重载_const对象

再来看看对const对象进行取地址:

const Date* operator&()const
{
	return this;
}

对于const对象的取地址重载,这里多了两个const,我将一一为你解释它们的意义。

首先我们来看第一个const,在这里我们需要返回对象的地址,也就是this,而this所指向的对象是const所修饰的。我们肯定不希望有人通过*this将对象进行修改,而在*的前面加const修饰的是*this也就是对象本身。

再来看看第二个const,首先我们需要知道类的成员函数的参数列表的第一个形参是隐藏的。

比如正常的你认为的成员函数长这样:

其实它长下面这样:

但是你会发现编译器对这个this进行了报错,那是因为C++规定不能在形参和实参中显式写出this,但是我们能在函数体内显式使用this:

当this指向的是const修饰的对象,那么*this也应该被const所修饰,但是我们又不能显式地写出const,所以C++规定这个const就写在成员函数参数列表的后面:

因此在任何不需要修改对象的成员函数的参数列表的后面,我们都可以加上const,以适用于被const所修饰的对象。




如果这篇文章有帮助到你,请留下您珍贵的点赞、收藏+评论,这对于我将是莫大的鼓励!学海无涯,共勉!😘😊😗💕💕😗😊😘




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

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

相关文章

Linux学习笔记5 值得一读,Linux(ubuntu)软件管理,搜索下载安装卸载全部搞定!(上)

本文记录Ubuntu操作系统的软件包管理。 一、背景 整个Linux系统就是大大小小的软件包构成的&#xff0c;在linux系统中&#xff0c;软件的管理非常重要&#xff0c;与其他操作系统不同&#xff0c;linux的软件包管理比较复杂&#xff0c;有时还需要处理软件包之间的冲突。本文…

Python | 泰勒图

写在前面 最近&#xff0c;开始对于CMIP6的一些数据进行评估。Talor图是一个很好展现模式间误差的方式&#xff0c;这里简单记录一下在python中的实现方式。 主要为半图的画法 参考的代码为&#xff1a; https://zenodo.org/records/5548061 效果大致下面这个样子 这边在原…

maven中如何配置多个仓库使其同时生效

场景 有一个项目&#xff0c;我把代码跟本地maven依赖包从同事那里拷贝过来&#xff0c;然后打包却一直打不了&#xff0c;一直报aliyun仓库找不到这个依赖的错误&#xff0c;无论我改成引用本地仓库还是线上aliyun仓库都不行。 依赖 <dependency><groupId>org.spr…

有三层交换机就不用路由器了?真的假的

号主&#xff1a;老杨丨11年资深网络工程师&#xff0c;更多网工提升干货&#xff0c;请关注公众号&#xff1a;网络工程师俱乐部 晚上好&#xff0c;我的网工朋友。 在现代企业网络环境中&#xff0c;三层交换机因其高效的数据包处理能力和较低的延迟而受到广泛欢迎。 然而&…

Python 从入门到实战7(元组)

我们的目标是&#xff1a;通过这一套资料学习下来&#xff0c;通过熟练掌握python基础&#xff0c;然后结合经典实例、实践相结合&#xff0c;使我们完全掌握python&#xff0c;并做到独立完成项目开发的能力。 之前的文章我们通过举例学习了python 中列表的定义及相关操作。今…

Echarts大屏可视化

构建可视化大屏&#xff1a; 构建布局&#xff1a;通过css和html对整个页面进行模块拆分&#xff0c;控制好每一张图的位置和大小&#xff0c;再将echarts实例化对象放到不同的盒子里 效果图&#xff1a; 代码&#xff1a; <!DOCTYPE html> <html lang"en&quo…

斯普林格-《土木工程与结构抗震设计》 Springer-Civil Engineering and Structural Seismic Design

文章目录 一、会议详情二、重要信息三、大会介绍四、出席嘉宾五、征稿主题六、咨询 一、会议详情 二、重要信息 大会官网&#xff1a;https://ais.cn/u/vEbMBz提交检索&#xff1a;EI Compendex、IEEE Xplore、Scopus最终截稿&#xff1a;2024年9月2日23:59 三、大会介绍 四…

关于vue中v-model绑定radio表单元素的说明

在学习中&#xff0c;老师讲在v-model中&#xff0c;绑定的是radio的checked属性&#xff0c;起初看了例子后很不理解&#xff0c;于是开始寻找答案 老师所说的绑定关系 老师给的绑定代码&#xff0c;怎么看来&#xff0c;都不是实例的gender变量绑定radio的checked属性&…

2024 MongoDB 中国用户大会上海站成功举办圆满结束: 技术驱动未来,携手共创辉煌

一年一度 2024 MongoDB 中国用户大会上海站顺利举办&#xff0c;感谢大家的积极参与&#xff01; 在数字化浪潮的背景下&#xff0c;随着人工智能、物联网、5G等前沿技术的快速发展&#xff0c;如何利用这些技术实现业务创新&#xff0c;已成为中国企业在激烈市场竞争中保持领…

Vivado+PetaLinux 系统搭建教程

PetaLinux 是基于 Yocto project DDR SDRAM 双倍数据率同步动态随机存取存储器&#xff08;英语&#xff1a;Double Data Rate Synchronous Dynamic Random Access Memory&#xff0c;简称DDR SDRAM&#xff09;为具有双倍资料传输率的SDRAM&#xff0c;其资料传输速度为系统主…

Matplotlib | 绘制饼图

目录 简介安装 Matplotlib开始绘制简单饼图添加标签添加百分比修改显示方式突出扇形设置标题修改颜色实践&#xff1a;绘制七大洲面积比例图 简介 饼图&#xff08;Pie Chart&#xff09;&#xff0c;用扇形的面积&#xff0c;也就是圆心角的度数来表示数量。 饼图能够十分直…

【Java】ApiPost请求返回 `406` 状态码(jackson)

Java系列文章目录 补充内容 Windows通过SSH连接Linux 第一章 Linux基本命令的学习与Linux历史 文章目录 Java系列文章目录一、前言二、学习内容&#xff1a;三、问题描述3.1 问题截图3.2 错误简介3.2.1 HTTP状态码 406 Not Acceptable3.2.2 序列化和反序列化 3.3 后端问题位置…

yaml文件查看模型的架构

最近在看hrnet模型代码&#xff0c;想查看hrnet的模型架构&#xff0c;输出一下&#xff0c;但是模型参数需要cfg&#xff0c;我就想着怎么把yaml文件导进来然后打印模型呢&#xff0c;直接chat就可以了&#xff0c;下面解释一下每一部分&#xff0c;非常的好理解 yaml文件格式…

传神论文中心|第24期人工智能领域论文推荐

在人工智能领域的快速发展中&#xff0c;我们不断看到令人振奋的技术进步和创新。近期&#xff0c;开放传神&#xff08;OpenCSG&#xff09;传神社区发现了一些值得关注的成就。传神社区本周也为对AI和大模型感兴趣的读者们提供了一些值得一读的研究工作的简要概述以及它们各自…

ChatGPT 3.5/4.0使用手册:解锁人工智能的无限潜能

1. 引言 在人工智能的浪潮中&#xff0c;ChatGPT以其卓越的语言理解和生成能力&#xff0c;成为了一个革命性的工具。它不仅仅是一个聊天机器人&#xff0c;更是一个能够协助我们日常工作、学习和创造的智能伙伴。随着ChatGPT 3.5和4.0版本的推出&#xff0c;其功能和应用范围…

3个免费好用的网站,可以转换PDF,提取MP3

今天分享的三个网站&#xff0c;分别用于文件转换PDF&#xff0c;QMC转MP3格式和配色网站。 TOPDF 这个网站是一个在线PDF转换工具&#xff0c;可以快速将文本文件、演示文稿、电子表格和图片转换为PDF格式。它支持多种文件格式&#xff0c;如AZW3、BMP、CHM、CSV、DjVu、DOC、…

秋招突击——算法练习——8/30、9/4——技巧题练习——复习{}——新作{只出现一次的数字、多数元素、颜色分类、下一个排列、寻找重复数}

文章目录 引言复习新作136、只出现一次的数字个人实现 169、多数元素个人实现 75、颜色分类个人实现参考实现 31、下一个排列个人实现参考实现 287寻找重复数个人实现参考实现 总结 引言 手撕的代码大部分都是出自于这里&#xff0c;还是要继续加强&#xff0c;把剩下一些零碎…

10分钟学会Jmeter的用法

一提到接口测试&#xff0c;通常大家会有这样的疑问&#xff1a;前端测试不是已经覆盖到各种业务逻辑了吗&#xff1f;为什么还要做接口测试&#xff0c;接口测试和前端测试是不是重复了&#xff1f;对于这个问题&#xff0c;可以从下面几个方面来解释&#xff1a; 什么是接口…

Ubuntu共享文件夹的设置

ubuntu的操作路径时&#xff1a;/mnt/hgfs/51C_share

Mongodb 4.2.25 安装教程

一、上传部署包 1.1上传mongodb包进入/usr/local目录&#xff0c;将mongodb-linux-x86_64-rhel70-4.2.25.tgz包传到该目录下。 cd /usr/local 二、安装 2.1解压 tar zxvf mongodb-linux-x86_64-rhel70-4.2.25.tgz 2.2修改名称 mv mongodb-linux-x86_64-rhel70-4.2.25/ mong…