《C++primer》5~6章总结

news2025/1/19 17:21:15

《C++Primer》

  • 语句
  • 函数

语句

  • if else 就C++而言,规定else与离它最近的尚未匹配的if匹配,从而消除程序的二义性,所以最好的处理方法就是养成习惯在if else 后面加一个花括号
  • swirch搭配case关键字使用,case关键字和它对应的值一起被称为case标签,case标签必须是整型常量表达式
char ch = getVal();
int ival = 42;
switch(ch) {
case 3.14: //错误,不是整数
case ival://错误,不是常量
	}

任何两个case标签的值不能相同,否则引发错误。
一般不要省略case分支最后的break语句,如果没有写break语句,最好加一段注释说清楚程序的逻辑。

  • do while
do 
	statement
while(condition);

对于do while来说先执行语句或者快,后判断条件,所以不允许在条件部分定义变量,因为变量必须先定义才能使用,如果在statement中使用,再在condition中定义的话是错误的。

  • break负责终止离它最近的while,do while,for,switch语句
  • continue只能出现在for,while ,do while中,只有当switch语句嵌套在迭代语句内部时,才能在switch里使用continue
  • 异常处理机制为程序中异常检测和异常处理两部分协作提供支持,在C++中,异常处理包括:
  1. throw 表达式 异常检测部分使用throw表达式来表示它遇到了无法处理的问题。我们说trow引发了异常
  2. try语句块 异常处理部分使用try语句块处理异常,语句块以 关键字try开始,并以一个或多个catch子句结束try语句块中代码抛出的异常通常会被某个catch子句处理,因为catch子句处理异常,所以它们也被称作异常处理代码。

异常讲解
5.25习题

 1 #include<iostream>
  2 using namespace std;
  3 int main()
  4 {
  5   int item1, item2;
  6   while(cin >> item1 >>item2) {
  7     try {
  8       if(item1 != item2) {
  9         throw "两个数不相等";
 10       }
 11     } catch (const char *s) {
 12       cout << s << "\nTry again?Enter y or n " << endl;
 13       char c;
 14       cin >>c;
 15       if (!cin || c == 'n') {
 16         break;
 17       }
 18     }
 19   }
 20   cout << "异常之后后面语句照样执行" << endl;                                                                                               
 21   return 0;
 22 }

在这里插入图片描述

函数

  • 函数形参和实参的区别
    形参是函数定义中声明的参数,用于接收函数调用时传递的值或表达式,他们在函数体内部使用。实参是在函数调用时传递给函数的值或表达式,用于填充函数定义中的形参,它们在函数调用语句中使用。正确使用形参和实参可以帮助我们编写更加清晰,简洁和刻度的函数调用语句,提高代码的可维护性和可重用性。
  • 静态局部变量 的生命周期 = 程序的生命周期,且只会初始化一次,储存位置是程序的静态储存区域,不是在堆栈中,静态储存区还有全局变量和常量,它的大小和位置在程序编译时就已经确定了。但是并不能保证静态局部变量一定存储在静态区中,可能因为编译器和平台而有所变化。
  • 函数的声明应该放在头文件中
    如果将声明放在源文件中的话会出现如下问题
  1. 多个源文件中声明可能不一致,如函数参数个数,类型和返回值等不同
  2. 函数重复定义,可能会导致链接问题。
  • 函数如果无需改变引用传参的值,最好将其声明为常量引用
bool add(const string &s1, const string &s2);
  • 当使用实参初始化形参时会忽略掉顶层const
    egvoid func(const int i);这个函数无论是int 还是const int都能传参
  • 尽量把函数不会改变的形参定义成常量引用,传参的权限只能缩小,不能放大,形参定义成常量引用,既能传参数为变量的实参,也能传参数为常量的实参。
  • 数组传参是以指针的形式传递给函数的,所以一开始函数并不知道数组的确切尺寸,此时在我已知传参的方式中还有一种额外方式,使用标准库中的begin和end函数
int arr[10] = {0};
print(begin(arr), end(arr));
  • 数组也可以引用传参 void print(int (&arr)[10]); 但是有限制,此时只能传递有十个整数的数组
  • 当使用argv中的实参时,一定要记得可选的实参从argv[1]开始;argv[0]保存程序的名字,而非用户输入。
    含有可变形参的函数,如果所有的实参类型相同,可以传递一个名为initializer_list的标准库类型。initializer_list类型定义在同名的头文件中,它提供的操作如下:
initializer_list<T> lst;
		默认初始化; T类型元素的空列表
initializer_list<T> lst{a, b, c...};
		lst的元素类型和初始值一样多;lst的元素是对应初始值的副本;列表中的元素是const
lst2(lst)或lst2 = lst;
拷贝或赋值一个initializer_list对象不会拷贝列表中的元素;拷贝后原始列表和副本共享元素
lst.size()  列表中元素的数量
lst.begin() 返回指向lst中首元素的指针
lst.end() 返回指向lst中尾元素下一位置的指针

和vector一样,initializer_list 也是一种模版类型,因此定义initializer_list对象时,必须说明列表中所含元素的类型。
eg

initializer_list的元素类型是string
initializer_list<string> ls;
initializer_list的元素类型是int
initializer_list<int> li;

如果想向initializer_list中传递一个值的序列,则必须把序列放在一对花括号内:

  3 void error_msg(initializer_list<string> il)
  4 {
  5   for(auto beg = il.begin(); beg != il.end(); ++beg) {
  6     cout<< *beg << " ";
  7     cout << endl;
  8   }
  9 }
 10 int main()
 11 {
 12   int a;
 13   cin >> a;
 14   if(a != 1) {
 15     error_msg({"function", "hello", "world"});                                                                                              
 16   }

含有initializer_list形参的函数也可以同时拥有其他形参,例如如果上述函数的第一个参数是int,第二个参数是initializer_list,则传入时可以在原来的基础前填一个int整数
注:在范围for中循环使用initializer_list对象时,应该将循环控制变量声明成引用类型,并且引用的类型应该是const &
因为initializer_list对象的元素是const类型不可修改,并且如果不用引用的话,会增加额外的拷贝。

  • 不要返回局部对象的引用或指针,函数一旦完成后,局部对象将被释放掉,一旦释放掉以后指针或引用将指向一个不存在的对象。要想确保返回值安全,必须确保在函数调用完成之后该对象依旧存在,或者说该对象指向的空间依然存在
  • C++11规定,函数可以返回花括号包围的值的列表。
    eg:
11 vector<string> process()  
 12 {  
 13   //..  
 14   //expected 和 actual 是string的对象  
 15   string expected, actual;  
 16   if(expected.empty()) {                                                                                                                    
 17       return {};     //返回一个空的vector对象  
 18       } else if (expected == actual) {  
 19       return {"functionX", "okey"};  // 返回列表初始化的vector对象  
 20       } else {  
 21       return {"functionX",expected, actual};   
 22       }  
 23 } 

如果函数返回的是内置类型,则花括号包围的列表最多包含一个值,如果返回的是类类型,由类本身定义初始值如何使用,也就是类类用返回值初始化。

  • 声明一个返回数组只指针的函数有时候返回值会显得十分复杂
    eg
    int (*func(int i))[10]该函数的名字是func,形参类型是int返回值是指向含有10个整形数组的指针
    在c++11中有一种可以简化上述func声明的方法,就是使用尾置返回类型

为了表示真正的返回类型跟在形参列表之后,我们在本应该出现返回类型的地方防止一个auto
auto func(int i) -> int(*)[10];

  • 函数重载 在同一个作用域内的几个函数名字相同但是形参列表不同。
  • 一个拥有顶层const的形参无法和另一个没有顶层的形参区分开来,他们二者不能实现函数重载,而拥有底层const的形参与非常量对象可以实现函数重载。
25 Record lookup(Phone);                                                                                                         
 26 Record lookup(const Phone);                                                                                                   
 27 //重复声明了Record lookup(Phone)                                                                                              
 28                                                                                                                               
 29 Record lookup(Account&); //函数作用于Account的引用                                                                            
 30 Record lookup(const Account&);//函数作用于常量引用 

前面两个函数不能构成重载,此时调用函数无法区分开
后面两个可以,因为常量只能调用常量版本的,虽然非常量对象可以转化成const对象进而调用const版本,但当我们传递一个非常量对象或者指向非常量对象的指针时,编译器会优先选用非常量版本的函数。

  • const_cast 和重载 const_cast只能改变运算对象的底层const,其在重载函数的情景中最有用
    举个例子:
5 //比较两个string对象的长度,返回较短的那个引用
  6 const string &shorterString(const string &s1, const string &s2)                                                                             
  7 {
  8   return s1.size() <= s2.size() ? s1 : s2;  
  9 }
 10 /*
 11  * 该函数的参数和返回类型都是const string 的引用 
 12  * 我们可以对两个非常量的string实参调用这个函数 
 13  * 但返回的结果仍然是const string&
 14  */
 15 
 16 //运用const_cast达到传入的实参不是常量,但是中间调用上述函数
 17 //返回值不是常量
 18 string &shorterString(string &s1, string &s2)
 19 {
 20   auto &r = shorterString(const_cast<const string&>(s1),
 21                           const_cast<const string&>(s2));
 22   return const_cast<string&>(r);
 23 }
 24 /*                                                                                              
 25  * 这个函数,首先将实参强制转化成const的引用,然后调用
 26  * shorterString函数的const版本,const版本返回对const string&的引用 
 27  * 然后我们再将其转换回一个普通的string&

  • 当调用重载函数会出现如下三种情况
  1. 编译器找到一个与实参最佳匹配的函数,并生成调用该函数的代码
  2. 找不到任何一个函数与调用的实参匹配,此时编译器发出无匹配的错误信息
  3. 有多于一个函数可以匹配,但是每一个都不是明显的最佳选择,此时也将发生错误,称为二义性调用
  • 函数重载必须在同一个作用域。
  • 在c++语言中,名字查找发生在类型检查之前。
  • 上述中我们编写了一个小函数,作用是比较两个string形参的长度并返回长度较小的string引用,把这种规模较小的操作定义成函数可以提高代码的复用率,并且修改操作变得更加容易,但将操作定义成函数存在一个潜在的缺点,函数调用比一般求等价表达式的值要慢一点,在大多数机器上,一次函数调用其实包含着一系列工作:调用前要先保存寄存器,并在返回时恢复;可能需要拷贝实参;程序转向一个新的位置继续执行
  • 内联函数可避免函数调用的开销
    将函数指定为内联函数,通常就是将它在每个调用点上"内联的“展开”。
    在函数的返回类型前面加上关键字inline,就可以将它声明成内联函数了
    eg inline const string shorterStirng(const string &s1, const string &s2);
    内联说明只是向编译器发出一个请求,编译器可以忽略这个请求,一般而言,内联机制用于优化规模较小,流程直接,频繁调用的函数。
  • constexpr函数 是指能用于常量表达式的函数,为了能在编译过程中随时展开,constexpr函数被隐式地指定为内联函数,但是是允许constexpr函数的返回值并非一个常量
    eg:
 7 constexpr int new_sz() { return 42; }                                                                                                     
    8 constexpr int foo = new_sz(); // 正确,fool是一个常量表达式
    9 //如果arg是常量表达式,则scale(arg) 也是常量表达式
   10 constexpr size_t scale(size_t cnt) { return new_sz() * cnt;}
   11 int arr[scale(2)];//正确,scale(2)是常量表达式
   12 int i = 2; // i不是常量
E> 13 int a2[scale(i)]; //错误:scale不是常量表达式

  • assert是一种预处理宏,执行运行时检查,其行为依赖预一个名为NDEBUG的预处理变量的状态,即如果定义了NDEBUG,则assert什么也不做,默认状态下没有定义NDEBUG,则assert将执行运行时检查。同时,很多编译器都提供了一个命令行选项是我们可以定义预处理变量。
    g++ -D NDEBUG test.cc -o test加上-D NDUBUG就可以
  • 函数匹配
    在大多数情况下,我们容易确定某次调用应该选用哪个重载函数,但是如果几个重载函数的形参数量相等以及某些形参的类型可以由其他类型转换得来时,函数调用就不怎么容易了。
    以下面的函数为例
  7 void f();
  8 void f(int);
  9 void f(int, int);
 10 void f(double, double = 3.14);  

如果出现f(5.6) 问,此时会调用哪个函数

  1. 先选与被调用函数的同名函数
    在这个例子中,四个函数都是同名函数
  2. 形参梳理与本次调用提供的实参数量相等
  3. 每个实参的类型与对应的形参类型相等,或者能转换成形参的类型
    因此上述四个函数中
    我们首先能根据实参的数量排除两个,剩下的使用一个int实参和两个double(其中一个有缺省量)是可以的。
    f(int) 是可行的,double可以转化成int
    f(double, double = 3.14) 也是可以的,因为第二个参数类型完全一致,都是double,所以此时匹配是f(double, double = 3.14;
    基本思想:实参类型与形参类型越接近,他们匹配的越好
    如果是调用f((42,3.14),c此时根据第一条规则,在f(int, int) 与f(double, double = 3.14)但是发现如果只看第一个参数的话f(int, int)适合,只看第二个参数的话f(double, double = 3.14适合,编译器最终将这个调用具有二义性而拒绝请求。
    注:调用重载函数时,应尽量避免强制类型转换,如果在实际应用中确实需要强制类型转换,则说明我们设计的形参集合不合理。
  • 函数指针指向函数,和其他指针一样,函数指针指向特定类型,函数指针的类型由它的返回类型和形参类型共同决定,与函数名无关。
    eg
    bool (*pf) (const string&, const string&);
    pf先与*结合说明其是一个指针,将名字拿掉此时剩下的就是指针指向的类型了,该类型是形参为两个cosnt string&以及返回值是bool的函数。
    当我们把函数名作为一个值使用时,该函数自动转换成指针。
    我们还能直接使用函数的指针调用该函数。
    在指向不同函数的指针间不存在类型转换规则。
  • 函数指针形参
11 void useBigger(const string &s1, const string &s2,
 12                 bool (*pf)(const string&, const string&)); 

若把函数作为实参使用,此时它会自动转换成指针
eg

useBigger(s1, s2, lengthCompare);

如上所示,直接使用函数指针显得冗长而繁琐,使用typedefdecltype可以简化使用了函数的代码

 13 //Func 和 Func2是函数类型
 14 typedef bool Func(const string&, const string&);
 15 typedef decltype(lengthCompare) Func2;                                                                                                      
 16 //FuncP和FuncP2是指向函数的指针
 17 typedef bool(* Func)(const string&, const string&);
 18 typedef decltype(lengthCompare)(*Func2);

需要注意的是decltype返回的是函数类型,并不是函数指针,此时我们要自己加上*才表示函数指针。

  • 返回指向函数的指针
    eg
int (*f1(int))(int, int);

该函数名为f1,参数为一个int,返回指向函数形参为两个int,且返回值为int函数的指针。

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

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

相关文章

PCB~地平面

地平面的特征 • 在同一块板子上&#xff0c;无线数字信号经常会有较高的数字逻辑&#xff0c;例如高增益的RF电路 • 屏蔽和接地对于接收端的设计是非常有效的 – 辐射在源端就应该被屏蔽掉 – 地平面电流应该回到源端 – 电源电流会通过最小电阻和电感路径回到源端 • 至少有…

Git的项目管理工具的使用

Git的项目管理工具的使用 为什么学习Git软件&#xff1f; 主流开发中&#xff0c;基于互联网的开发项目都会使用git进行资源管理 资源管理&#xff1a;人力资源 ​ 代码资源 : .java .c . js 等 ​ 文档资源 &#xff1a; doc.md ,pdf 等 git是最常用的scm软件&#xff08;Soft…

Vivado综合属性系列之九 CLOCK_BUFFER_TYPE

目录 一、前言 二、CLOCK_BUFFER_TYPE ​ ​2.1 属性说明 ​ ​2.2 工程代码 ​ ​2.3 结果 一、前言 ​ ​在设计中&#xff0c;对于时钟端口驱动时钟单元时&#xff0c;工具会自动综合出全局时钟BUFG连接时钟源和时钟负载。当存在全局时钟BUFG不足或者因为某些…

3512. 最短距离总和

Powered by:NEFU AB-IN Link 文章目录 3512. 最短距离总和题意思路代码 3512. 最短距离总和 题意 给定一张带权无向完全图&#xff0c;设点的编号为 1,2,3,4,5…n&#xff08;以邻接矩阵的形式给出&#xff09;。 计算依次拿走第 i个点后&#xff0c;剩余所有点到其他点的最短…

从零开始Vue3+Element Plus后台管理系统(十二)——封装Axios,取消重复请求

在过往的项目中&#xff0c;大部分Axios在项目搭建时就直接二次封装好了&#xff0c;拿来即用。满足通用需求是没有问题的&#xff0c;但碰到一些特别的接口返回&#xff0c;弱网场景&#xff0c;特别的产品需求&#xff0c;就觉得简单的封装不够用了。 实际上Axios非常强大&a…

在Windows上安装Docker与k8s,完美亲测!

一、软件准备 1、去Docker官网下载Docker Desktop&#xff0c;并一键安装 2、下载k8s-for-docker-desktop包 git clone https://github.com/AliyunContainerService/k8s-for-docker-desktop.git二、镜像源配置 配置docker的国内镜像&#xff0c;国外的网络下载可能比较慢 { …

在线考试系统设计

一&#xff0e;项目概述 使⽤⽬前较为流⾏的技术栈开发的⼀款界⾯设计友好、部署操作简单、代码层次结构清晰、⼆次开发上⼿便捷的在线考试平台。系统分为管理端和考⽣端&#xff0c;管理端集成了用户管理、⻆⾊管理、部⻔管理、菜单管理、数据字典、系统⽇志、定时任务、中间件…

软件设计师 试题三

问题一&#xff1a;补充用例图&#xff0c;他就是参与者&#xff08;左边文章里的&#xff09;与用例&#xff08;用户的行为&#xff09;之间的关系&#xff0c;比如用户执行某些事情 一个句号一个功能 。找参与者做的事行为 。或者就是根据参与者对面提供的信息去文中找相关…

【Linux初阶】进程替换的应用 - 简易命令行解释器的实现

&#x1f31f;hello&#xff0c;各位读者大大们你们好呀&#x1f31f; &#x1f36d;&#x1f36d;系列专栏&#xff1a;【Linux初阶】 ✒️✒️本篇内容&#xff1a;使用代码手段实现一个简易的命令行解释器&#xff0c;其中功能包括&#xff1a;打印输出提示符、获取用户输入…

实验11 人工神经网络(2)

1. 实验目的 ①掌握梯度下降法的优化算法&#xff1b; ②能够使用tf.keras构建Sequential模型&#xff0c;完成多分类任务。 2. 实验内容 ①下载MNIST数据集&#xff0c;建立神经网络模型&#xff0c;实现对MNIST手写数字数据集的识别&#xff0c;调整超参数和训练参数&…

wps js宏编辑器案例3-工作簿和工作表操作

本文通过一个连锁门店每天营业额按门店名称进行拆分的案例&#xff0c;讲述wps js宏编辑器中工作簿、工作表和Range的相关操作&#xff0c;比如&#xff1a;工作表的复制&#xff0c;工作簿另存&关闭&#xff0c;Range.findNext使用注意实现等&#xff0c;案例已上传到gite…

Android学习专题】java基本概念及日常问题处理(学习记录)

java程序的入口函数 java入口函数只有一种&#xff0c;而且必须以main命名&#xff0c;且以public static进行修饰。 入口(Entry of Program)&#xff1a;指程序运行的起点。 只有main方法可以作为程序的入口。 main方法结构&#xff1a;public static void main(String[] arg…

Meaning of life: The patch of life

这世界上每一个人都不是完美的&#xff0c;生活也是如此&#xff0c;一场电影、一次旅行、一把游戏、一次畅谈都是生命的"补丁"&#xff0c; 生活总有不顺心的时候&#xff0c;但我们也要继续前行。 The patch of life Not long ago, My daughters frosting shoes w…

chatgpt赋能Python-python_bold

Python Bold&#xff1a;强劲的SEO工具 在当今数字化的时代&#xff0c;搜索引擎优化&#xff08;SEO&#xff09;基本上是每个企业成功的重要因素之一。然而SEO并不是一项易于处理的任务。面对越来越激烈的竞争&#xff0c;只有使用最好的工具才能真正成功。而Python Bold就是…

即时通讯(IM)开源项目OpenIM对WebAssembly支持,提升web端体验

WebAssembly 是什么&#xff1f; 2019 年 12 月&#xff0c;W3C 标准批准了第四种官方语言&#xff1a;WebAssembly (Wasm)。这种语言在结构、使用和功能方面与以前的语言有很大不同。 WebAssembly 是一种新的编码方式&#xff0c;可以在现代的Web浏览器中运行 &#xff0d; …

[CTF/网络安全] 攻防世界 Web_php_include 解题详析(php伪协议、data伪协议、file伪协议)

[CTF/网络安全] 攻防世界 Web_php_include 解题详析 代码审计PHP_include文件包含漏洞及伪协议PayloadPHP伪协议恶意 PHP 伪协议data伪协议恶意 data 伪协议file伪协议恶意 file 伪协议 知识点及姿势读取目录路径dirname(FILE)读取目录路径实例读取目录文件glob读取目录文件实例…

chatgpt赋能Python-python_check_module

Python Check Module简介 Python是一个非常流行的编程语言&#xff0c;具有易学、易用的特点&#xff0c;因此在算法、数据分析等领域广泛使用。Python Check Module是Python的一个模块&#xff0c;可以用于对Python代码进行静态分析&#xff0c;检测代码中的潜在问题&#xf…

chatgpt赋能Python-python_canal

Python Canal: 让你的代码流畅无阻 Python Canal 是一个简单易用的Python 并行工具&#xff0c;可以帮助你提高应用程序的性能。它使用了现代操作系统的资源管理能力来有效地管理你的多进程和多线程应用程序&#xff0c;这可以使你的应用程序更轻松地处理大规模数据和异步任务…

Python集合:让你的数据去重变得更简单!

集合set是一个无序的、不可重复的元素集合。 如果你想学习自动化测试&#xff0c;我这边给你推荐一套视频&#xff0c;这个视频可以说是B站百万播放全网第一的自动化测试教程&#xff0c;同时在线人数到达1000人&#xff0c;并且还有笔记可以领取 B站讲的最详细的Python接口自…

使用Win-flex bison生成一个计算器(VS2022)

本文参考网页“Flex和Bison简介和Windows下使用入门”&#xff08; Flex和Bison简介和Windows下使用入门 | 码农家园 &#xff09;&#xff0c;使用Win-flex bison生成生成一个计算器&#xff08;VS2022&#xff09;。 1. 使用VS2022创建空项目 使用VS2022创建名为MyProject的…