类与对象(中(2))

开头

大家好啊,上一期内容我们介绍了类与对象中六大默认成员函数中的两种--->构造函数与析构函数,相信大家多少都形成了自己的独到见解。那么今天,我将继续就拷贝构造函数与运算符重载函数来展开讲解,话不多说,我们进入正题~~

拷贝构造

概念

相信大家在生活中多少都见过双胞胎吧,由于某些原因,他们的外形几乎一致。那么在类与对象中,我们是否可以创建一个与已存在对象一致的新对象呢?---Of course!它便是拷贝构造。

拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用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;
}

C++规定:

内置类型直接拷贝(浅拷贝/值拷贝)

自定义类型必须调用拷贝构造完成拷贝

这就能很好解释为什么不能传值调用(会引发无限递归,编译器一般会直接报错)

3. 若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。

关于深拷贝与浅拷贝,后期会专门拎出来出一期博客,此处不过多解释~

下面我们通过代码进行更深入的理解:

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::Time(const 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;

	// 用已经存在的d1拷贝构造d2,此处会调用Date类的拷贝构造函数
	// 但Date类并没有显式定义拷贝构造函数,则编译器会给Date类生成一个默认的拷贝构
	造函数
		Date d2(d1);
	return 0;
}

如图,由于d1为自定义类型,但由于其没有显示定义的拷贝构造函数,编译器先给Date类生成一个默认拷贝构造函数并赋予其默认值:

调用时由于Date类型内有一个自定义类型Time,故编译器会先跳入Time类调用拷贝构造,如下图:

看一下运行结构:

注意:在编译器生成的默认拷贝构造函数中,内置类型是按照字节方式直接拷贝的,而自定义类型是调用其拷贝构造函数完成拷贝的。

4. 编译器生成的默认拷贝构造函数已经可以完成字节序的值拷贝

我们再来看一串代码:

// 这里会发现下面的程序会崩溃掉?这里就需要用到深拷贝去解决。
typedef int DataType;
class Stack
{
public:
	Stack(size_t capacity = 10)
	{
		_array = (DataType*)malloc(capacity * sizeof(DataType));
		if (nullptr == _array)
		{
			perror("malloc申请空间失败");
			return;
		}
		_size = 0;
		_capacity = capacity;
	}
	void Push(const DataType& data)
	{
		// CheckCapacity();
		_array[_size] = data;
		_size++;
	}
	~Stack()
	{
		if (_array)
		{
			free(_array);
			_array = nullptr;
			_capacity = 0;
			_size = 0;
		}
	}
private:
	DataType* _array;
	size_t _size;
	size_t _capacity;
};
int main()
{
	Stack s1;
	s1.Push(1);
	s1.Push(2);
	s1.Push(3);
	s1.Push(4);
	Stack s2(s1);
	return 0;
}

我们用一张图来理解:

简单来说,浅拷贝的缺点

1.拷贝的对象与原对象共用一块空间,等到程序结束时自动调用的析构函数将会对同一块空间释放两次

2.修改其中一个对象时将会影响另一个对象

**注意:类中如果没有涉及资源申请时,拷贝构造函数是否写都可以;一旦涉及到资源申请时,则拷贝构造函数是一定要写的,否则就是浅拷贝。

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

1.使用已存在对象创建新对象

2.函数参数类型为类类型对象

3.函数返回值类型为类类型对象

此图对应下方代码:

class Date
{
public:
	Date(int year, int minute, int day)
	{
		cout << "Date(int,int,int):" << this << endl;
	}
	Date(const Date& d)
	{
		cout << "Date(const Date& d):" << this << endl;
	}
	~Date()
	{
		cout << "~Date():" << this << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
Date Test(Date d)
{
	Date temp(d);
	return temp;
}
int main()
{
	Date d1(2022, 1, 13);
	Test(d1);
	return 0;
}

为了提高程序效率,一般对象传参时,尽量使用引用类型,返回时根据实际场景,能使用引用尽量使用引用哦~


补充

我们就构造函数与运算符重载函数做一个简单的区分:

构造函数:用一个已经存在的对象初始化另一个对象。

运算符重载函数:已经存在的两个对象之间的赋值拷贝。

默认成员函数不能写到全局。

运算符重载函数建议写到类里边,否则易受到访问限定符的限制


赋值运算符重载

运算符重载

C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其 返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。

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

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

注意:

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

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

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

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

5.  (.*)  (::)   (sizeof)   (? :)  ( . )   注意以上5个运算符不能重载。

// 全局的operator==
class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	//private:
	int _year;
	int _month;
	int _day;
};
// 这里会发现运算符重载成全局的就需要成员变量是公有的,那么问题来了,封装性如何保证?
// 重载成成员函数。
bool operator==(const Date& d1, const Date& d2)
{
	return d1._year == d2._year
		&& d1._month == d2._month
		&& d1._day == d2._day;
}
void Test()
{
	Date d1(2018, 9, 26);
	Date d2(2018, 9, 27);
    //(d1==d2)等价于 d1.operator==(d2)
	cout << (d1 == d2) << endl;
}


class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}

	// bool operator==(Date* this, const Date& d2)
	// 这里需要注意的是,左操作数是this,指向调用函数的对象
	bool operator==(const Date & d2)
	{
		return  _year == d2._year
				&& _month == d2._month
				&& _day == d2._day;
	}
private:
	int _year;
	int _month;
	int _day;
};

大家可以细细品一下上方的代码哦~


赋值运算符重载

1.运算符重载格式

(*下方T为自定义类型)

参数类型:const T&,传递引用可以提高传参效率

返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值

检测是否自己给自己赋值

返回*this :要复合连续赋值的含义

特别的,任何指针类型都是内置类型~

来看代码:

class Date
{
public:
	//构造函数
	Date(int year = 1900, 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& operator=(const Date& d)
	{
		if (this != &d)
		{
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}

		return *this;
	}
private:
	int _year;
	int _month;
	int _day;
};

上方便是赋值运算符重载函数的格式,它的调用方式如下:

Date d1(2024,8,20);
Date d2(2024,8,19);
d1.operator=(d2);

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)
{
	if (&left != &right)
	{
		left._year = right._year;
		left._month = right._month;
		left._day = right._day;
	}
	return left;
}

3. 用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝。

注 意:内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值。

默认生成赋值重载跟拷贝构造行为一样:
1、内置类型成员--值拷贝/浅拷贝(Date和MyQueue不需要我们自己实现赋值重载)
2、自定义类型成员会去调用他的赋值重载(Stack需要我们自己实现,因为默认生成是浅拷贝)

class Time
{
public:
	Time()
	{
		_hour = 1;
		_minute = 1;
		_second = 1;
	}
	Time& operator=(const Time& t)
	{
		//this指针指向的是d1的地址
		if (this != &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;
}

那么问题来了,既然编译器生成的默认赋值运算符重载函数已经可以完成字节序的值拷贝了,那还需要我们自己实现吗?当然像日期类这样的类是没必要的。那么下面的类呢?我们来验证一下:

typedef int DataType;
class Stack
{
public:
	Stack(size_t capacity = 10)
	{
		_array = (DataType*)malloc(capacity * sizeof(DataType));
		if (nullptr == _array)
		{
			perror("malloc申请空间失败");
			return;
		}
		_size = 0;
		_capacity = capacity;
	}
	void Push(const DataType& data)
	{
		// CheckCapacity();
		_array[_size] = data;
		_size++;
	}
	~Stack()
	{
		if (_array)
		{
			free(_array);
			_array = nullptr;
			_capacity = 0;
			_size = 0;
		}
	}
private:
	DataType* _array;
	size_t _size;
	size_t _capacity;
};
int main()
{
	Stack s1;
	s1.Push(1);
	s1.Push(2);
	s1.Push(3);
	s1.Push(4);
	Stack s2;
	s2 = s1;
	return 0;
}

可以看到运行崩溃了,这又是为什么呢?这里先买个关子,后面的深拷贝会继续讲解~

这里我们先用一张图来理解为什么:

我们可以得出一个结论:如果类中未涉及到资源管理,赋值运算符是否实现都可以;一旦涉及到资源管理则必须要实现。


前置++和后置++重载

通过上面的分享,不知你是否对运算符重载有了一定的了解----我们趁热打铁,来了解一下它的延伸用法。

先来看看同一个函数的不同实现方法:

int main()
{
	Date d;
	Date d1(2022, 1, 13);
	d = d1++;    // d: 2022,1,13   d1:2022,1,14
	d = ++d1;    // d: 2022,1,15   d1:2022,1,15
	return 0;
}

我们不妨来思考一下,哪种实现方式更为高效呢?

是的!毋庸置疑是第二种(它所开辟的临时变量相较于第一种明显更少)。

日期类的实现

接下来我们再来看看日期类的实现:

class Date
{
public:
	// 获取某年某月的天数
	int GetMonthDay(int year, int month)
	{
		static int days[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30,
	   31 };
		int day = days[month];
		if (month == 2
			&& ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
		{
			day += 1;
		}
		return day;
	}

	// 全缺省的构造函数
	Date(int year = 1900, int month = 1, int day = 1);
	// 拷贝构造函数
 // d2(d1)
	Date(const Date& d);

	// 赋值运算符重载
 // d2 = d3 -> d2.operator=(&d2, d3)
	Date& operator=(const Date& d);
	// 析构函数
	~Date();
	// 日期+=天数
	Date& operator+=(int day);
	// 日期+天数
	Date operator+(int day);
	// 日期-天数
	Date operator-(int day);
	// 日期-=天数
	Date& operator-=(int day);
	// 前置++
	Date& operator++();
	// 后置++
	Date operator++(int);
	// 后置--
	Date operator--(int);
	// 前置--
	Date& operator--();

	// >运算符重载
	bool operator>(const Date& d);
	// ==运算符重载
	bool operator==(const Date& d);
	// >=运算符重载
	bool operator >= (const Date& d);

	// <运算符重载
	bool operator < (const Date& d);
	// <=运算符重载
	bool operator <= (const Date& d);
	// !=运算符重载
	bool operator != (const Date& d);
	// 日期-日期 返回天数
	int operator-(const Date& d);
private:
	int _year;
	int _month;
	int _day;
};

配套的实现来咯~我们仅需写一个operator<与operator==,而后便只需要运用重载知识对其进行调用,便能一一实现。

bool Date::operator<(const Date& x)
{
	if (_year < x._year)
	{
		return true;
	}
	else if (_year == x._year && _month < x._month)
	{
		return true;
	}
	else if (_year == x._year && _month == x._month && _day < x._day)
	{
		return true;
	}

	return false;
}

bool Date::operator==(const Date& x)
{
	return _year == x._year
		&& _month == x._month
		&& _day == x._day;
}

// 复用
// d1 <= d2
bool Date::operator<=(const Date& x)
{
	return *this < x || *this == x;
}

bool Date::operator>(const Date& x)
{
	return !(*this <= x);
}

bool Date::operator>=(const Date & x)
{
	return !(*this < x);
}

bool Date::operator!=(const Date& x)
{
	return !(*this == x);
}

int Date::GetMonthDay(int year, int month)
{
	static int daysArr[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
	//if (((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) && month == 2)
	if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
	{
		return 29;
	}
	else
	{
		return daysArr[month];
	}
}

Date& Date::operator+=(int day)
{
	_day += day;
	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);
		++_month;
		if (_month == 13)
		{
			++_year;
			_month = 1;
		}
	}

	return *this;
}

// d1 + 100
Date Date::operator+(int day)
{
	Date tmp(*this);
	tmp += day;
	return tmp;
}

// 前置++
Date& Date::operator++()
{
	*this += 1;
	return *this;
}

// 后置++
// 增加这个int参数不是为了接收具体的值,仅仅是占位,跟前置++构成重载
Date Date::operator++(int)
{
	Date tmp = *this;
	*this += 1;
	
	return tmp;
}

结尾

好了,以上便是本期的全部内容,如果对您有帮助,请动动您的小手指为我点个赞,万分感谢,我们一同进步!

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

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

相关文章

Python版《超级玛丽+源码》-Python制作超级玛丽游戏

小时候最喜欢玩的小游戏就是超级玛丽了&#xff0c;有刺激有又技巧&#xff0c;通关真的很难&#xff0c;救下小公主还被抓走了&#xff0c;唉&#xff0c;心累&#xff0c;最后还是硬着头皮继续闯&#xff0c;终于要通关了&#xff0c;之后再玩还是没有那么容易&#xff0c;哈…

十五年以来 — 战略性云平台服务的演进路径之全面呈现(含亚马逊、微软和谷歌)

Gartner每年都发布对全球IaaS平台进行评估的魔力象限报告。2023年底&#xff0c;Gartner将此项评估的名称改为“战略性云平台服务”&#xff08;Strategic cloud platform services&#xff09;&#xff0c;尽管其核心仍为IaaS&#xff0c;但是&#xff0c;毫无疑问&#xff0c…

手机云电脑游戏测评:ToDesk、易腾云、达龙云、青椒云四款对比分析

文章目录 &#x1f4d1; 引言一、背景概述测试目标 二、测试方案与评测标准2.1 测试设备2.2 评测标准 三、云电脑移动端实测3.1 ToDesk云电脑3.1.1 安装步骤与用户界面3.1.2 性能测试3.1.3 多场景适用性与兼容性3.1.4 性价比 3.2 易腾云电脑3.2.1 安装流程与用户界面3.2.2 帧率…

WebRTC为何成为视频开发领域的首选技术? EasyCVR视频转码助力无缝视频通信

随着互联网的飞速发展&#xff0c;视频通信已成为日常生活和工作中不可或缺的一部分。从在线教育、视频会议到远程医疗、在线直播&#xff0c;视频开发的需求日益增长。在这些应用场景中&#xff0c;选择何种技术来构建视频系统至关重要。 目前&#xff0c;在很多视频业务的开…

Golang | Leetcode Golang题解之第352题将数据流变为多个不相交区间

题目&#xff1a; 题解&#xff1a; type SummaryRanges struct {*redblacktree.Tree }func Constructor() SummaryRanges {return SummaryRanges{redblacktree.NewWithIntComparator()} }func (ranges *SummaryRanges) AddNum(val int) {// 找到 l0 最大的且满足 l0 < val…

Browserless 网页抓取:Playwright 中的 NodeJS

什么是 Playwright&#xff1f; Playwright 是一个用于 Web 测试和自动化的开源框架。基于 Node.js&#xff0c;由 Microsoft 开发&#xff0c;它通过单一 API 支持 Chromium、Firefox 和 WebKit。它可以在 Windows、Linux 和 macOS 上运行&#xff0c;并且兼容 TypeScript、J…

设计模式六大原则(一)--单一职责原则

摘要 单一职责原则是设计模式六大原则之一&#xff0c;强调一个类应该仅有一个引起它变化的原因&#xff0c;即每个类应仅负责一项职责。本文通过详细探讨单一职责原则的定义、实现方式、优缺点及其适用场景&#xff0c;揭示了其在软件设计中的核心地位。通过类的拆分、接口设…

TCP协议段中的六个标志位

目录 ACK SYN RST FIN PSH URG TCP报文格式中的六个标志位由6个比特构成&#xff0c;在通信双方基于TCP协议互相发送报文数据时可以通过报头中标志位来区别对方发送的报文数据的请示。 ACK 确认号是否有效。 接收端对所收到的报文进行检查&#xff0c;若未发现错误&…

周易测算系统开发:融合古典智慧与现代技术的创新实践

一、引言 周易&#xff0c;作为中国古代文化的瑰宝&#xff0c;蕴含着深邃的哲学思想与预测智慧&#xff0c;其独特的六十四卦体系及爻变原理&#xff0c;自古以来便被人们用于探索自然规律、人生哲理及未来趋势。随着科技的飞速发展&#xff0c;将周易智慧与现代计算机技术相结…

StackStorm自动化平台

1. StackStorm概述 1.1 StackStorm介绍 StackStorm是一个开源的事件驱动自动化平台&#xff0c;它允许开发者和系统管理员自动化IT和网络操作。StackStorm结合了IT运维、DevOps和网络安全团队的需求&#xff0c;提供了一个集中式的工作流自动化解决方案&#xff0c;包括事件响…

图像数据处理13

三、空域滤波 3.1滤波器的基本概念 什么是滤波&#xff1f; 简单来说就是从干扰信号中提取出有用的信号 3.1.1空域滤波&#xff08;Spatial Domain Filtering&#xff09; 空域滤波适用于简单的滤波任务&#xff0c;直接对图像的像素空间进行操作。它通过对图像中的每个像…

ES 支持乐观锁吗?如何实现的?

本篇主要介绍一下Elasticsearch的并发控制和乐观锁的实现原理&#xff0c;列举常见的电商场景&#xff0c;关系型数据库的并发控制、ES的并发控制实践。 并发场景 不论是关系型数据库的应用&#xff0c;还是使用Elasticsearch做搜索加速的场景&#xff0c;只要有数据更新&…

ES6-ES13学习笔记

目录 初识ES6 变量声明 解构赋值 对象解构 ​编辑 数组解构 ​编辑模版字符串 字符串扩展 includes() repeat() startsWith() endsWith() 数值扩展 二进制和八进制表示法 &#xff08;Number.&#xff09;isFinite()与isNaN() Number.isInteger() Math.trunc …

AWS不同类型的EC2实例分别适合哪些场景?

Amazon Web Services&#xff08;AWS&#xff09;的弹性计算云&#xff08;EC2&#xff09;提供了多种实例类型&#xff0c;以满足不同的应用需求和工作负载。了解不同类型的 EC2 实例及其适用场景&#xff0c;可以帮助用户更好地优化性能和控制成本。九河云和大家一起了解一下…

元数据管理gravitino学习

元数据管理的组成有几个部分&#xff1a;Metaservice(Gravitino)、Luoshu&#xff08;amoro)、Hive Metastore&#xff0c;其中gravitino是数据管理模块实现元数据统一管理的核心。前面有提到hive metastore可以存储hive的库表元数据信息&#xff0c;可以用于存储关于hive表、列…

一文读懂推荐系统

随着互联网的飞速发展&#xff0c;信息过载已经成为了一个普遍的问题。我们每天都要面对大量的内容&#xff0c;却很难找到真正符合自己兴趣和需求的信息。这时&#xff0c;推荐系统应运而生&#xff0c;它能够根据用户的兴趣和行为&#xff0c;智能地推荐相关内容&#xff0c;…

思特科技:国家宝藏数字体验馆展现东方美学 让“文物活起来”

01      思特科技为“国家宝藏数字体验展”提供“数字技术”支持&#xff0c;带来国宝的数字化演绎。以《国家宝藏》顶级IP为基础&#xff0c;打造的全新沉浸文化项目“国宝数字体验展“&#xff0c;借由文物的视角、站在历史的星河中&#xff0c;探寻时间长河中不变的智慧…

Mac文件需要分卷压缩怎么办 Mac上怎么解压分卷压缩的文件

在处理大型文件的传输和存储的时候&#xff0c;Mac用户常面临文件大小超过限制的问题。为了有效管理这些大文件&#xff0c;分卷压缩成为一种必不可少的解决方案。Mac文件需要分卷压缩怎么办&#xff1f;Mac上怎么解压分卷压缩的文件&#xff1f;本文将向你介绍如何使用BetterZ…

近视防控明星:蔡司小乐圆中期临床数据详解

近视防控明星&#xff1a;蔡司小乐圆中期临床数据详解 小乐圆镜片作为近视防控镜片里的明星产品&#xff0c;从22年5月上市以来防控效果就一直备受大家的关注。而最近中期临床试验的结果&#xff0c;给家长孩子吃了一颗定心丸。 本次实验中&#xff0c;240位受试者被随机分成三…

C语言函数详解(上)【库函数】

目录 前言 一、函数的概念 二、库函数 1.标准库和头文件 2.库函数使用方式 3.如何通过以上的网站查看库函数信息 &#xff08;以sqrt为例&#xff09; 3.1 功能 3.2 头文件包含 3.3 库函数文档的⼀般格式 1. 函数原型 ​编辑2. 函数功能介绍 ​编辑3. 参数和返…