图源:文心一言
听课笔记简单整理,供小伙伴们参考,包含以下内容“🐋3.11 引用类型、🐋3.14 内联函数、🐋3.15 默认参数值、🐋3.16 函数重载、🐋3.17 C++系统函数”~🥝🥝
- 第1版:听课的记录代码~🧩🧩
编辑:梅头脑🌸
审核:文心一言
目录
🐳课程来源
🐳函数
🐋3.11 引用类型
🐋3.14 内联函数
🐋3.15 默认参数值
🐋3.16 函数重载
🐋3.17 C++系统函数
🔚结语
🐳课程来源
- 郑莉老师的公开课:🌸C++语言程序设计基础 - 清华大学 - 学堂在线 (xuetangx.com)
🐳函数
🐋3.11 引用类型
🧩题目
输入两个整数交换后输出(值传递)
📇算法思路
因为返回值只能返回1个值,而不能返回2个数字交换过的值,所以这个题目使用引用。
⌨️算法代码
#include <iostream>
using namespace std;
void swap(int& a, int& b) {
int t = a;
a = b;
b = t;
}
int main()
{
int x = 5, y = 10;
cout << "x = " << x << ", y = " << y << endl;
swap(x, y);
cout << "x = " << x << ", y = " << y << endl;
return 0;
}
📇执行结果
📇代码解释
当进行值交换时,注意函数声明
void swap(int& a, int& b)
。如果修改为void swap(int a, int b)
,则无法完成值的交换功能。原因是,在后一种情况下,a
和b
是通过值传递的,即传递的是x
和y
的副本。虽然在swap
函数内部更改了a
和b
的值,但这些更改不会影响到原始的x
和y
。而通过在参数前加上引用符号
&
,我们实际上传递的是x
和y
的地址。这样,在函数内部对a
和b
所做的任何修改都会直接反映在原始的x
和y
上,从而实现了值的交换。
引用在C++中是一个很有用的特性,它提供了对变量的直接别名访问,而不是通过指针的间接访问。虽然引用在某些情况下可能引发安全问题(比如悬挂引用,即引用了一个已经被销毁的对象的引用),但这并不意味着引用本身不安全或应该避免使用。相反,当正确使用时,引用可以提高代码的可读性和效率。
以下是一些推荐使用引用的场景:
函数参数:当你想在函数内部修改传递进来的变量时,引用是一个很好的选择。通过传递引用而不是值,你可以避免复制的开销,并且函数可以直接修改原始数据。
返回值:虽然通常建议通过值返回小型对象,但对于大型对象或容器(如
std::vector
、std::string
等),通过引用返回可能更有效。然而,需要注意的是,你不能返回局部变量的引用,因为局部变量在函数返回后会被销毁,导致悬挂引用。在这种情况下,你应该返回一个新对象或传递一个输出参数。避免复制开销:当处理大型对象或数据结构时,通过引用传递它们可以避免复制整个对象的开销。
多态性:在面向对象编程中,引用经常与基类和派生类一起使用,以实现多态行为。通过基类引用调用虚函数时,会调用相应对象类型的实现。
范围基于的for循环:C++11引入了范围基于的for循环,它使用引用来遍历容器中的元素,避免了不必要的复制。
性能优化:在某些性能关键的场景中,使用引用可以避免不必要的内存分配和释放,从而提高程序的性能。
然而,需要注意的是,过度使用引用也可能导致代码难以理解和维护。因此,在使用引用时应该权衡其优点和潜在的复杂性。
🐋3.14 内联函数
🧩题目
计算圆的面积。
📇算法思路
本例仅涉及到乘法,为了提高计算效率,使用内联函数。
⌨️算法代码
#include <iostream>
using namespace std;
const double PI = 3.14159265358979;
inline double calArea(double radius) {
return PI * radius * radius;
}
int main()
{
double r = 3.0;
double area = calArea(r);
cout << area << endl;
return 0;
}
📇执行结果
📇代码解释
本行代码
inline double calArea(double radius)
中的inline
关键字表明calArea
函数是一个内联函数。内联函数(Inline Function)是C++中的一种函数优化技术。通过在函数声明前添加
inline
关键字,开发者可以建议编译器将函数的调用替换为函数体本身的代码,这种替换通常发生在编译时期。内联函数的目的是减少函数调用的开销,提高程序的执行效率。内联函数的特点:
- 内联替换:内联函数的代码通常会被直接插入到调用点(可以简单理解为函数直接粘在main函数中执行),从而消除函数调用的开销,如参数压栈、跳转到函数体、执行函数后返回等。
- 编译时期决定:是否真正内联一个函数是由编译器在编译时期决定的。
inline
关键字只是对编译器的建议,编译器可以选择忽略它(具体来说,比较机智的编译器可以自己识别哪些适合作为内联函数编译,哪些不适合)。- 定义在头文件中:由于内联函数的代码需要在每个调用点都可用,因此内联函数通常定义在头文件中,以便在包含该头文件的每个源文件中都可见。
- 适用于小型函数:内联最适合那些体积小、执行速度快且调用频繁的函数。对于大型函数,内联可能会导致代码膨胀,反而降低性能。
- 无函数调用开销,但有代码膨胀风险:内联可以避免函数调用的开销,但如果一个函数被内联多次,它的代码就会在最终的可执行文件中出现多次,导致代码膨胀。
使用内联函数的注意事项:
- 内联函数应该简洁且执行快速,避免包含循环和递归调用。
- 避免在头文件中定义大型的内联函数,这会导致包含该头文件的每个源文件都包含该函数的完整代码,增加编译时间和最终可执行文件的大小。
- 谨慎使用内联,特别是在性能敏感的代码中。通过性能测试和剖析来确定是否真的需要内联某个函数。
🐋3.15 默认参数值
🧩题目
计算长方体的体积。
📇算法思路
emm...长方体的体积 = 长 x 宽 x 高 这样子...
⌨️算法代码
#include <iostream>
#include <iomanip>
using namespace std;
int getVolume(int length, int width = 3, int height = 3);
int main()
{
const int X = 10, Y = 12, Z = 15;
cout << "Some box data is ";
cout << getVolume(X, Y, Z) << endl;
cout << "Some box data is ";
cout << getVolume(X, Y) << endl;
cout << "Some box data is ";
cout << getVolume(X) << endl;
return 0;
}
int getVolume(int length, int width, int height) {
cout << setw(5) << length << setw(5) << width << setw(5) << height << '\t';
return length * width * height;
}
📇执行结果
📇代码解释
- int getVolume(int length, int width = 3, int height = 3); 这段代码,表示 width 与 height均有默认初始值,但用户也可以自行输入 width 与 height 的参数覆盖这2个默认值,例如:
- cout << getVolume(X, Y, Z) << endl; 这段代码,传入 length = X = 10,width = Y = 12,height = Z = 15;
- cout << getVolume(X, Y) << endl; 这段代码,传入 length = X = 10,width = Y = 12,height = 3(默认值);
- cout << getVolume(X) << endl; 这段代码,传入 length = X = 10,width = 3(默认值),height = 3(默认值);
注意:
默认参数的顺序:默认参数必须从右到左连续。也就是说,如果一个参数有默认值,那么它右边的所有参数也都必须有默认值。例如:
int func(int a, int b = 10, int c = 20); // 合法 int func(int a = 10, int b, int c = 20); // 错误!'b' 没有默认值,但 'a' 有。
- 默认参数与函数重载:默认参数可以被视为函数重载的一种简化形式。但是,当同时使用默认参数和函数重载时,需要注意可能产生的歧义。编译器会优先选择参数最匹配的函数,而不是选择有更多默认参数的函数。
- 默认参数的值:默认参数的值可以是常量、全局变量,甚至可以是函数。但是,默认参数的值在函数声明时确定,而不是在函数调用时确定。因此,如果默认参数是一个变量,那么该变量的值将是函数声明时的值,而不是函数调用时的值。
- 默认参数在头文件中定义:通常,函数的声明放在头文件中,而函数的定义放在源文件中。当使用默认参数时,应将默认参数放在函数声明中(即在头文件中),而不是在函数定义中。这样可以确保所有包含该头文件的源文件都能看到相同的默认参数。
🐋3.16 函数重载
🧩题目
求 整数、浮点数的平方和。
📇算法思路
功能相同,但仅参数类型与返回类型不同的两个函数,可以使用函数重载(使用同一个名称),以方便程序员的调用。
⌨️算法代码
#include <iostream>
using namespace std;
int sumOfSquare(int a, int b) {
return a * a + b * b;
}
double sumOfSquare(double a, double b) {
return a * a + b * b;
}
int main()
{
int m, n;
cout << "Enter two integer:";
cin >> m >> n;
cout << "Their sum of square:" << sumOfSquare(m, n) << endl;
double x, y;
cout << "Enter two real number:";
cin >> x >> y;
cout << "Their sum of square:" << sumOfSquare(x, y) << endl;
return 0;
}
📇执行结果
输入整数:3 5,浮点数:3.5 5.5的执行结果:
📇代码解释
int sumOfSquare(int a, int b) 与 double sumOfSquare(double a, double b) ,函数名相同,但是参数类型与返回类型不同,属于函数重载。
函数重载是指在同一作用域内,可以有一组具有相同名字但参数数量或类型不同的函数。编译器会根据调用时提供的参数数量和类型来选择最合适的函数进行调用。
函数重载的注意事项:
参数差异:重载的函数必须通过参数的数量、类型或顺序来区分。仅仅返回类型的不同并不足以构成重载。
最佳匹配:当调用重载函数时,编译器会尝试找到与提供的参数最匹配的函数。如果没有找到确切匹配,编译器可能会尝试通过隐式类型转换来找到匹配,这可能会导致不期望的行为。
避免歧义:设计重载函数时,要确保不会出现歧义性调用。例如,如果两个重载函数都可以通过隐式类型转换来匹配同一组参数,编译器将无法决定应该调用哪一个,从而导致编译错误。对于重载函数,每个重载都应该有清晰的文档和注释,说明它的用途、参数和返回值。这有助于其他开发者理解和使用这些函数。
谨慎使用默认参数:默认参数和函数重载在某些情况下可以互换使用,但它们有不同的优缺点。使用默认参数可以减少需要编写的函数数量,但可能会使函数签名变得复杂。而函数重载可以提供更清晰的语义,但可能会导致更多的代码重复。在选择时,应根据具体情况权衡利弊。
🐋3.17 C++系统函数
🧩题目
求 特定角度的三角函数计算值。
📇算法思路
调用库函数 cmath 中的 sin、cos、tan~
⌨️算法代码
#include <iostream>
#include <cmath>
using namespace std;
const double PI = 3.14159265358979;
int main()
{
double angle;
cout << "Please enter an angle:";
cin >> angle;
double radian = angle * PI / 180;
cout << "sin(" << angle << ") = " << sin(radian) << endl;
cout << "cos(" << angle << ") = " << cos(radian) << endl;
cout << "tan(" << angle << ") = " << tan(radian) << endl;
return 0;
}
📇执行结果
输入整数:30 的执行结果:
📇知识扩展
C++常用库
C++ 标准库提供了大量的函数和类,用于处理各种常见的编程任务。以下是一些 C++ 中常用的库函数和它们所属的库:
输入/输出流库 (iostream)
std::cin
: 用于从标准输入读取数据。std::cout
: 用于向标准输出写入数据。std::cerr
: 用于向标准错误输出写入数据。std::clog
: 用于向标准日志输出写入数据。字符串库 (string)
std::string
: 表示字符串的类。std::getline()
: 从输入流中读取一行文本。std::stoi()
,std::stol()
,std::stoll()
: 将字符串转换为整数。std::stof()
,std::stod()
,std::stold()
: 将字符串转换为浮点数。容器库 (vector, map, set, etc.)
std::vector
: 可动态调整大小的数组。std::map
: 关联数组,存储键值对。std::set
: 存储唯一元素的集合。std::unordered_map
,std::unordered_set
: 无序的 map 和 set。算法库 (algorithm)
std::sort()
: 对容器中的元素进行排序。std::find()
: 在容器中查找元素。std::binary_search()
: 对已排序的容器进行二分查找。std::transform()
: 对容器中的元素进行转换。数值库 (numeric)
std::accumulate()
: 计算容器中元素的累积和或其他二元操作的累积结果。std::inner_product()
: 计算两个容器的内积。std::iota()
: 为容器中的元素填充连续的递增值。文件流库 (fstream)
std::ifstream
: 用于从文件读取数据的输入文件流。std::ofstream
: 用于向文件写入数据的输出文件流。std::fstream
: 可用于读写文件的文件流。时间库 (chrono)
std::chrono::system_clock
: 获取系统时间。std::chrono::steady_clock
: 获取稳定的时间间隔,不受系统时间调整影响。std::chrono::duration_cast()
: 转换时间间隔的精度。线程库 (thread)
std::thread
: 表示线程的类。std::this_thread::sleep_for()
: 使当前线程休眠指定的时间间隔。std::mutex
: 互斥锁,用于同步线程。异常处理库 (exception)
std::exception
: 所有标准异常的基类。std::throw_with_nested()
: 抛出嵌套异常。std::rethrow_if_nested()
: 重新抛出嵌套异常(如果有)。其他常用库
std::random
: 用于生成随机数。std::regex
: 用于正则表达式匹配和操作。std::atomic
: 用于多线程编程中的原子操作。std::optional
: 表示可能包含值或为空的包装器。这只是 C++ 标准库中的一小部分。实际上,C++ 标准库非常庞大,提供了各种各样的功能来支持各种编程需求。在使用这些库时,建议查阅相关的文档和参考资料以获取更详细的信息和示例代码。
🔚结语
博文到此结束,写得模糊或者有误之处,期待小伙伴留言讨论与批评,督促博主优化内容{例如有错误、难理解、不简洁、缺功能}等,博主会顶锅前来修改~~😶🌫️😶🌫️
我是梅头脑,本片博文若有帮助,欢迎小伙伴动动可爱的小手默默给个赞支持一下,感谢点赞小伙伴对于博主的支持~~🌟🌟
同系列的博文:🌸数据结构_梅头脑_的博客-CSDN博客
同博主的博文:🌸随笔03 笔记整理-CSDN博客