本文知识点导图

函数

函数基础

一个典型的函数定义包括以下部分: 返回类型,函数名字,右0个或多个形参组成的列表以及函数体。
一个函数的定义包含四部分

#mermaid-svg-zxN4tqeXy5FjjHxD .label{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);fill:#333;color:#333}#mermaid-svg-zxN4tqeXy5FjjHxD .label text{fill:#333}#mermaid-svg-zxN4tqeXy5FjjHxD .node rect,#mermaid-svg-zxN4tqeXy5FjjHxD .node circle,#mermaid-svg-zxN4tqeXy5FjjHxD .node ellipse,#mermaid-svg-zxN4tqeXy5FjjHxD .node polygon,#mermaid-svg-zxN4tqeXy5FjjHxD .node path{fill:#ECECFF;stroke:#9370db;stroke-width:1px}#mermaid-svg-zxN4tqeXy5FjjHxD .node .label{text-align:center;fill:#333}#mermaid-svg-zxN4tqeXy5FjjHxD .node.clickable{cursor:pointer}#mermaid-svg-zxN4tqeXy5FjjHxD .arrowheadPath{fill:#333}#mermaid-svg-zxN4tqeXy5FjjHxD .edgePath .path{stroke:#333;stroke-width:1.5px}#mermaid-svg-zxN4tqeXy5FjjHxD .flowchart-link{stroke:#333;fill:none}#mermaid-svg-zxN4tqeXy5FjjHxD .edgeLabel{background-color:#e8e8e8;text-align:center}#mermaid-svg-zxN4tqeXy5FjjHxD .edgeLabel rect{opacity:0.9}#mermaid-svg-zxN4tqeXy5FjjHxD .edgeLabel span{color:#333}#mermaid-svg-zxN4tqeXy5FjjHxD .cluster rect{fill:#ffffde;stroke:#aa3;stroke-width:1px}#mermaid-svg-zxN4tqeXy5FjjHxD .cluster text{fill:#333}#mermaid-svg-zxN4tqeXy5FjjHxD div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);font-size:12px;background:#ffffde;border:1px solid #aa3;border-radius:2px;pointer-events:none;z-index:100}#mermaid-svg-zxN4tqeXy5FjjHxD .actor{stroke:#ccf;fill:#ECECFF}#mermaid-svg-zxN4tqeXy5FjjHxD text.actor>tspan{fill:#000;stroke:none}#mermaid-svg-zxN4tqeXy5FjjHxD .actor-line{stroke:grey}#mermaid-svg-zxN4tqeXy5FjjHxD .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333}#mermaid-svg-zxN4tqeXy5FjjHxD .messageLine1{stroke-width:1.5;stroke-dasharray:2, 2;stroke:#333}#mermaid-svg-zxN4tqeXy5FjjHxD #arrowhead path{fill:#333;stroke:#333}#mermaid-svg-zxN4tqeXy5FjjHxD .sequenceNumber{fill:#fff}#mermaid-svg-zxN4tqeXy5FjjHxD #sequencenumber{fill:#333}#mermaid-svg-zxN4tqeXy5FjjHxD #crosshead path{fill:#333;stroke:#333}#mermaid-svg-zxN4tqeXy5FjjHxD .messageText{fill:#333;stroke:#333}#mermaid-svg-zxN4tqeXy5FjjHxD .labelBox{stroke:#ccf;fill:#ECECFF}#mermaid-svg-zxN4tqeXy5FjjHxD .labelText,#mermaid-svg-zxN4tqeXy5FjjHxD .labelText>tspan{fill:#000;stroke:none}#mermaid-svg-zxN4tqeXy5FjjHxD .loopText,#mermaid-svg-zxN4tqeXy5FjjHxD .loopText>tspan{fill:#000;stroke:none}#mermaid-svg-zxN4tqeXy5FjjHxD .loopLine{stroke-width:2px;stroke-dasharray:2, 2;stroke:#ccf;fill:#ccf}#mermaid-svg-zxN4tqeXy5FjjHxD .note{stroke:#aa3;fill:#fff5ad}#mermaid-svg-zxN4tqeXy5FjjHxD .noteText,#mermaid-svg-zxN4tqeXy5FjjHxD .noteText>tspan{fill:#000;stroke:none}#mermaid-svg-zxN4tqeXy5FjjHxD .activation0{fill:#f4f4f4;stroke:#666}#mermaid-svg-zxN4tqeXy5FjjHxD .activation1{fill:#f4f4f4;stroke:#666}#mermaid-svg-zxN4tqeXy5FjjHxD .activation2{fill:#f4f4f4;stroke:#666}#mermaid-svg-zxN4tqeXy5FjjHxD .mermaid-main-font{font-family:"trebuchet ms", verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-zxN4tqeXy5FjjHxD .section{stroke:none;opacity:0.2}#mermaid-svg-zxN4tqeXy5FjjHxD .section0{fill:rgba(102,102,255,0.49)}#mermaid-svg-zxN4tqeXy5FjjHxD .section2{fill:#fff400}#mermaid-svg-zxN4tqeXy5FjjHxD .section1,#mermaid-svg-zxN4tqeXy5FjjHxD .section3{fill:#fff;opacity:0.2}#mermaid-svg-zxN4tqeXy5FjjHxD .sectionTitle0{fill:#333}#mermaid-svg-zxN4tqeXy5FjjHxD .sectionTitle1{fill:#333}#mermaid-svg-zxN4tqeXy5FjjHxD .sectionTitle2{fill:#333}#mermaid-svg-zxN4tqeXy5FjjHxD .sectionTitle3{fill:#333}#mermaid-svg-zxN4tqeXy5FjjHxD .sectionTitle{text-anchor:start;font-size:11px;text-height:14px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-zxN4tqeXy5FjjHxD .grid .tick{stroke:#d3d3d3;opacity:0.8;shape-rendering:crispEdges}#mermaid-svg-zxN4tqeXy5FjjHxD .grid .tick text{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-zxN4tqeXy5FjjHxD .grid path{stroke-width:0}#mermaid-svg-zxN4tqeXy5FjjHxD .today{fill:none;stroke:red;stroke-width:2px}#mermaid-svg-zxN4tqeXy5FjjHxD .task{stroke-width:2}#mermaid-svg-zxN4tqeXy5FjjHxD .taskText{text-anchor:middle;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-zxN4tqeXy5FjjHxD .taskText:not([font-size]){font-size:11px}#mermaid-svg-zxN4tqeXy5FjjHxD .taskTextOutsideRight{fill:#000;text-anchor:start;font-size:11px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-zxN4tqeXy5FjjHxD .taskTextOutsideLeft{fill:#000;text-anchor:end;font-size:11px}#mermaid-svg-zxN4tqeXy5FjjHxD .task.clickable{cursor:pointer}#mermaid-svg-zxN4tqeXy5FjjHxD .taskText.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-zxN4tqeXy5FjjHxD .taskTextOutsideLeft.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-zxN4tqeXy5FjjHxD .taskTextOutsideRight.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-zxN4tqeXy5FjjHxD .taskText0,#mermaid-svg-zxN4tqeXy5FjjHxD .taskText1,#mermaid-svg-zxN4tqeXy5FjjHxD .taskText2,#mermaid-svg-zxN4tqeXy5FjjHxD .taskText3{fill:#fff}#mermaid-svg-zxN4tqeXy5FjjHxD .task0,#mermaid-svg-zxN4tqeXy5FjjHxD .task1,#mermaid-svg-zxN4tqeXy5FjjHxD .task2,#mermaid-svg-zxN4tqeXy5FjjHxD .task3{fill:#8a90dd;stroke:#534fbc}#mermaid-svg-zxN4tqeXy5FjjHxD .taskTextOutside0,#mermaid-svg-zxN4tqeXy5FjjHxD .taskTextOutside2{fill:#000}#mermaid-svg-zxN4tqeXy5FjjHxD .taskTextOutside1,#mermaid-svg-zxN4tqeXy5FjjHxD .taskTextOutside3{fill:#000}#mermaid-svg-zxN4tqeXy5FjjHxD .active0,#mermaid-svg-zxN4tqeXy5FjjHxD .active1,#mermaid-svg-zxN4tqeXy5FjjHxD .active2,#mermaid-svg-zxN4tqeXy5FjjHxD .active3{fill:#bfc7ff;stroke:#534fbc}#mermaid-svg-zxN4tqeXy5FjjHxD .activeText0,#mermaid-svg-zxN4tqeXy5FjjHxD .activeText1,#mermaid-svg-zxN4tqeXy5FjjHxD .activeText2,#mermaid-svg-zxN4tqeXy5FjjHxD .activeText3{fill:#000 !important}#mermaid-svg-zxN4tqeXy5FjjHxD .done0,#mermaid-svg-zxN4tqeXy5FjjHxD .done1,#mermaid-svg-zxN4tqeXy5FjjHxD .done2,#mermaid-svg-zxN4tqeXy5FjjHxD .done3{stroke:grey;fill:#d3d3d3;stroke-width:2}#mermaid-svg-zxN4tqeXy5FjjHxD .doneText0,#mermaid-svg-zxN4tqeXy5FjjHxD .doneText1,#mermaid-svg-zxN4tqeXy5FjjHxD .doneText2,#mermaid-svg-zxN4tqeXy5FjjHxD .doneText3{fill:#000 !important}#mermaid-svg-zxN4tqeXy5FjjHxD .crit0,#mermaid-svg-zxN4tqeXy5FjjHxD .crit1,#mermaid-svg-zxN4tqeXy5FjjHxD .crit2,#mermaid-svg-zxN4tqeXy5FjjHxD .crit3{stroke:#f88;fill:red;stroke-width:2}#mermaid-svg-zxN4tqeXy5FjjHxD .activeCrit0,#mermaid-svg-zxN4tqeXy5FjjHxD .activeCrit1,#mermaid-svg-zxN4tqeXy5FjjHxD .activeCrit2,#mermaid-svg-zxN4tqeXy5FjjHxD .activeCrit3{stroke:#f88;fill:#bfc7ff;stroke-width:2}#mermaid-svg-zxN4tqeXy5FjjHxD .doneCrit0,#mermaid-svg-zxN4tqeXy5FjjHxD .doneCrit1,#mermaid-svg-zxN4tqeXy5FjjHxD .doneCrit2,#mermaid-svg-zxN4tqeXy5FjjHxD .doneCrit3{stroke:#f88;fill:#d3d3d3;stroke-width:2;cursor:pointer;shape-rendering:crispEdges}#mermaid-svg-zxN4tqeXy5FjjHxD .milestone{transform:rotate(45deg) scale(0.8, 0.8)}#mermaid-svg-zxN4tqeXy5FjjHxD .milestoneText{font-style:italic}#mermaid-svg-zxN4tqeXy5FjjHxD .doneCritText0,#mermaid-svg-zxN4tqeXy5FjjHxD .doneCritText1,#mermaid-svg-zxN4tqeXy5FjjHxD .doneCritText2,#mermaid-svg-zxN4tqeXy5FjjHxD .doneCritText3{fill:#000 !important}#mermaid-svg-zxN4tqeXy5FjjHxD .activeCritText0,#mermaid-svg-zxN4tqeXy5FjjHxD .activeCritText1,#mermaid-svg-zxN4tqeXy5FjjHxD .activeCritText2,#mermaid-svg-zxN4tqeXy5FjjHxD .activeCritText3{fill:#000 !important}#mermaid-svg-zxN4tqeXy5FjjHxD .titleText{text-anchor:middle;font-size:18px;fill:#000;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-zxN4tqeXy5FjjHxD g.classGroup text{fill:#9370db;stroke:none;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);font-size:10px}#mermaid-svg-zxN4tqeXy5FjjHxD g.classGroup text .title{font-weight:bolder}#mermaid-svg-zxN4tqeXy5FjjHxD g.clickable{cursor:pointer}#mermaid-svg-zxN4tqeXy5FjjHxD g.classGroup rect{fill:#ECECFF;stroke:#9370db}#mermaid-svg-zxN4tqeXy5FjjHxD g.classGroup line{stroke:#9370db;stroke-width:1}#mermaid-svg-zxN4tqeXy5FjjHxD .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5}#mermaid-svg-zxN4tqeXy5FjjHxD .classLabel .label{fill:#9370db;font-size:10px}#mermaid-svg-zxN4tqeXy5FjjHxD .relation{stroke:#9370db;stroke-width:1;fill:none}#mermaid-svg-zxN4tqeXy5FjjHxD .dashed-line{stroke-dasharray:3}#mermaid-svg-zxN4tqeXy5FjjHxD #compositionStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-zxN4tqeXy5FjjHxD #compositionEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-zxN4tqeXy5FjjHxD #aggregationStart{fill:#ECECFF;stroke:#9370db;stroke-width:1}#mermaid-svg-zxN4tqeXy5FjjHxD #aggregationEnd{fill:#ECECFF;stroke:#9370db;stroke-width:1}#mermaid-svg-zxN4tqeXy5FjjHxD #dependencyStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-zxN4tqeXy5FjjHxD #dependencyEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-zxN4tqeXy5FjjHxD #extensionStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-zxN4tqeXy5FjjHxD #extensionEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-zxN4tqeXy5FjjHxD .commit-id,#mermaid-svg-zxN4tqeXy5FjjHxD .commit-msg,#mermaid-svg-zxN4tqeXy5FjjHxD .branch-label{fill:lightgrey;color:lightgrey;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-zxN4tqeXy5FjjHxD .pieTitleText{text-anchor:middle;font-size:25px;fill:#000;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-zxN4tqeXy5FjjHxD .slice{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-zxN4tqeXy5FjjHxD g.stateGroup text{fill:#9370db;stroke:none;font-size:10px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-zxN4tqeXy5FjjHxD g.stateGroup text{fill:#9370db;fill:#333;stroke:none;font-size:10px}#mermaid-svg-zxN4tqeXy5FjjHxD g.statediagram-cluster .cluster-label text{fill:#333}#mermaid-svg-zxN4tqeXy5FjjHxD g.stateGroup .state-title{font-weight:bolder;fill:#000}#mermaid-svg-zxN4tqeXy5FjjHxD g.stateGroup rect{fill:#ECECFF;stroke:#9370db}#mermaid-svg-zxN4tqeXy5FjjHxD g.stateGroup line{stroke:#9370db;stroke-width:1}#mermaid-svg-zxN4tqeXy5FjjHxD .transition{stroke:#9370db;stroke-width:1;fill:none}#mermaid-svg-zxN4tqeXy5FjjHxD .stateGroup .composit{fill:white;border-bottom:1px}#mermaid-svg-zxN4tqeXy5FjjHxD .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px}#mermaid-svg-zxN4tqeXy5FjjHxD .state-note{stroke:#aa3;fill:#fff5ad}#mermaid-svg-zxN4tqeXy5FjjHxD .state-note text{fill:black;stroke:none;font-size:10px}#mermaid-svg-zxN4tqeXy5FjjHxD .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.7}#mermaid-svg-zxN4tqeXy5FjjHxD .edgeLabel text{fill:#333}#mermaid-svg-zxN4tqeXy5FjjHxD .stateLabel text{fill:#000;font-size:10px;font-weight:bold;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-zxN4tqeXy5FjjHxD .node circle.state-start{fill:black;stroke:black}#mermaid-svg-zxN4tqeXy5FjjHxD .node circle.state-end{fill:black;stroke:white;stroke-width:1.5}#mermaid-svg-zxN4tqeXy5FjjHxD #statediagram-barbEnd{fill:#9370db}#mermaid-svg-zxN4tqeXy5FjjHxD .statediagram-cluster rect{fill:#ECECFF;stroke:#9370db;stroke-width:1px}#mermaid-svg-zxN4tqeXy5FjjHxD .statediagram-cluster rect.outer{rx:5px;ry:5px}#mermaid-svg-zxN4tqeXy5FjjHxD .statediagram-state .divider{stroke:#9370db}#mermaid-svg-zxN4tqeXy5FjjHxD .statediagram-state .title-state{rx:5px;ry:5px}#mermaid-svg-zxN4tqeXy5FjjHxD .statediagram-cluster.statediagram-cluster .inner{fill:white}#mermaid-svg-zxN4tqeXy5FjjHxD .statediagram-cluster.statediagram-cluster-alt .inner{fill:#e0e0e0}#mermaid-svg-zxN4tqeXy5FjjHxD .statediagram-cluster .inner{rx:0;ry:0}#mermaid-svg-zxN4tqeXy5FjjHxD .statediagram-state rect.basic{rx:5px;ry:5px}#mermaid-svg-zxN4tqeXy5FjjHxD .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#efefef}#mermaid-svg-zxN4tqeXy5FjjHxD .note-edge{stroke-dasharray:5}#mermaid-svg-zxN4tqeXy5FjjHxD .statediagram-note rect{fill:#fff5ad;stroke:#aa3;stroke-width:1px;rx:0;ry:0}:root{--mermaid-font-family: '"trebuchet ms", verdana, arial';--mermaid-font-family: "Comic Sans MS", "Comic Sans", cursive}#mermaid-svg-zxN4tqeXy5FjjHxD .error-icon{fill:#522}#mermaid-svg-zxN4tqeXy5FjjHxD .error-text{fill:#522;stroke:#522}#mermaid-svg-zxN4tqeXy5FjjHxD .edge-thickness-normal{stroke-width:2px}#mermaid-svg-zxN4tqeXy5FjjHxD .edge-thickness-thick{stroke-width:3.5px}#mermaid-svg-zxN4tqeXy5FjjHxD .edge-pattern-solid{stroke-dasharray:0}#mermaid-svg-zxN4tqeXy5FjjHxD .edge-pattern-dashed{stroke-dasharray:3}#mermaid-svg-zxN4tqeXy5FjjHxD .edge-pattern-dotted{stroke-dasharray:2}#mermaid-svg-zxN4tqeXy5FjjHxD .marker{fill:#333}#mermaid-svg-zxN4tqeXy5FjjHxD .marker.cross{stroke:#333}:root { --mermaid-font-family: "trebuchet ms", verdana, arial;}#mermaid-svg-zxN4tqeXy5FjjHxD {color: rgba(0, 0, 0, 0.75);font: normal normal normal normal 16px/26px -apple-system, "SF UI Text", Arial, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", sans-serif;}

函数定义
返回类型 return type
函数名字 function name
0或多个形参列表 parameter list
函数体 function body

通过调用运算符来执行函数。
调用运算符的形式是一对圆括号,它作用于一个表达式,该表达式是函数或者指向函数的指针;
圆括号之内是一个用逗号隔开的实参列表。
函数的返回类型不能是数组类型或函数类,但可以是指向数组或函数的指针。

局部对象

在C++语言中,名字有作用域,对象有生命周期:

  • 名字的作用域是程序文本的一部分,名字在其中可见。
  • 对象的生命周期是程序执行过程中该对象存在的一段时间。

函数体是一个语句块,块构成一个新的作用域,我们可以在其中定义变量。

形参和函数体内部定义的变量统称为局部变量。

自动对象

我们把只存在于块执行期间的对象称为自动对象。
形参是一种自动对象。

局部静态对象

某些时候,有必要令局部变量的生命周期贯穿函数调用及之后的时间。可以将局部变量定义成static类型从而获得这样的对象。
局部静态对象在程序执行路径经过对象定义语句时初始化,并且直到程序终止才被销毁,在此期间即使对象所在的函数结束执行也不会对它有影响。

static 英[ˈstætɪk] 美[ˈstætɪk]
adj. 静止的; 静态的; 停滞的; 静力的;
n. 天电(干扰); 静电; 静力学;

举个例子,下面的函数统计它自己被调用了多少次:

   size_t count_calls(){static size_t ctr = 0;//调用结束后,这个值仍然有效。return ++ctr;}int main(){for(size_t i = 0; i != 10; ++i)cout <<  count_calls() << endl;return 0;}

函数声明

函数的名字也必须在使用之前声明。类似于变量,函数只能定义一次,但可以声明多次。唯一的例外,如果一个函数永远也不会被我们用到,那么它可以只有声明没有定义。

函数的声明和函数的定义非常类似,唯一的区别是函数声明无需函数体,用一个分号代替即可。

因为函数声明不含函数体,所以也无需形参的名字,事实上,在函数声明中经常省略形参的名字。

函数三要素(返回类型,函数名,形参类型)描述了函数的接口,函数声明也称为函数原型。

函数建议在头文件中声明在源文件中定义。

分离式编程

分离式编程允许我们把程序分割到几个文件中去,每个文件独立编译。

对我们用的代码进行编译会生成可执行文件.exe

如果我们修改了其中一个源文件,只需要重新编译那个改动了文件,通常会生成一个.obj(windows)或.o (Unix)文件。接下编译器负责把对象文件链接在一起形成可执行文件。

参数传递

和其他变量一样,形参的类型决定了形参和实参交互的方式。

如果形参是引用类型,它将绑定到对应的实参上,否则,将实参的值拷贝后赋给形参。

当形参是引用类型,我们说它对应的实参被引用传递,或者函数传应用调用。
当实参的值拷贝给形参时,形参和实参是两个相互独立的对象。我们说这样的实参被值传递,或者函数被传值调用。

传值参数

当执行指针拷贝操作是,拷贝的是指针的值,拷贝之后,两个指针是不同的指针。

因为指针可以间接地访问它所指的对象,所以通过指针可以修改它所指对象的值。

int function1(int *ip){*ip = 1;return *ip;
}int main(int argc, const char * argv[]) {int i = 0;int *p  = &i;i = function1(p);return 0;
}

本例中,i为指针指向的对象,p为实参,ip为形参。
函数调用时,ip复制p的值,也就是i的地址。
所以ip与p都指向i。 当修改*ip时,i的值也会被改动。
关系如下图

传引用参数

通过引用形参,允许函数改变一个或多个实参数的值。

 void reset(int &i){i = 0;    //改变了i所引用的对象的值}

调用时,直接传入对象即可,无需传递对象地址。

    int j = 42;reset(j);

使用引用避免拷贝

拷贝大的类类型对象或者容器对象比较低效,甚至有的类类型根本就不支持拷贝操作,当某种类型不支持拷贝操作时,函数只能通过引用形式访问该类型对象。

如,编写一个函数比较两个string对象的长度。

bool isShorter(const string &s1, const string &s2)
{return s1.size() < s2.size();
}

这里加上const是因为,如果无需改变引用形参的值,最好将其声明为常量引用。

使用应用形参返回额外信息

一个函数只能返回一个值,然而有时函数需要同时返回多个值,引用形参为我们一次返回多个值提供了有效的途径。

const形参和实参

这里可以回顾一下
形如 const int *p = &i ; 指向常量的指针
形如 int *const p = &i ; 常量指针

形如const int ci = 1; 或 int *const p = &i;这种作用于对象本身的const,称为顶层const

形参的顶层const会被忽略掉,传给他对象或者非常量对象都是可以的。
但是函数可以读取形参到值,不能向形参写值。

注意,在使用函数重用时:

   void fcn(const int i) { ...... }void fcn(int i) { ...... }

会被认为是同一个函数。

指针或引用形参与const

指针或引用形参的使用可以参照第二章第四节,初始化规则来对应。

尽量使用常量引用

把函数不会改变的形参定义成(普通的)引用是一种比较常见的错误。
这么做带给函数的调用者一种误导,即函数可以修改它的实参的值。

数组形参

数组有两个特殊的性质:不允许拷贝数组,使用数组时会将其转换成指针。

因为不能拷贝数组,所以我们无法以值传递的方式使用数组参数。
因为数组会被转换成指针,所以当我们为函数传递一个数组时,实际上传递的是指向数组首元素的指针。

形参的书写:

   //尽管书写形式不同,这三个函数其实是等价的。void print(const int*);void print(const int[]);void print(const int[10]);//这里的10,表示我们期望数组有多少个元素,实际上不一定。

函数调用

    int i = 0, j[2] = {0, 1};print(&i);print(j);//两者都是正确的。&i的类型是int *,j转换成int*并指向j[0]

因为数组是以指针形式传递给函数的,所以一开始函数并不知道数组的确切尺寸,调用者应该为此提供一些额外信息,管理指针形参有三种常见技术

使用标记制定数组长度

管理数组实参的第一种方法是要求数组本身包含一个结束标记,最典型的是C风格字符串。

    void print(const char *cp){  if(cp)               //若cp不是一个空指针while (*cp)    //只要指针所指的字符不是空字符count << *cp++;}

使用标准库规范

     void  print(const int *beg, const int *end){while(beg != end)cout << *beg++ <<endl;}//调用int j[2] = {0, 1 };print(begin(j), end(j));

显式传递一个表示数组大小的形参

      void print(const int ia[], size_t size){for (size_t i = 0; i != size; ++i)cout << ia[i] << endl;}//调用int j[] = {0, 1};print(j, end(j) - begin(j));

数组形参和const

当函数不需要对数组元素执行写操作时,数组形参应该是指向const的指针,只有当函数确实要改变元素的值时,才把指针指向非常量的指针。

数组引用形参

//形参是数组的引用,维度是类型的一部分
void print(int (&a)[10]){for (auto elem : arr)cout<< elem << endl;
}

(&a)的括号必不可少,
不存在引用的数组,只有数组的引用。

传递多维数组

当多维数组传递给函数时,真正传递的是指向数组首元素的指针。因为首元素本身就是一个数组,所以我们处理的是数组的数组。

//含有10个整数的数组的指针。void print(int (*matrix)[10], int rowSize)
//等价于 void print(int matrix[][10], int rowSIze)

再次强调*matrix两端的括号必不可少
int *matrix[10]; //10个指针构成的数组
int (*martrix)[10]; //指向含有10个整数数组的指针。

main:处理命令行选项

假定main函数位于prog可执行文件之内,我们可以向程序传递下面的选项:

 prog -d -o ofile data0

这些命令行选项通过两个可选的形参传递个main函数。

int  main(int argc, char *argv[]) {...}

第二个形参是一个数组,他的元素是指向C风格字符串的指针。
第一个形参表示数组种字符串的数量。
因为第二个形参是数组所以也可以定义成

 int main(int argc, char **argv){...}

上例的命令行为例,argc为5,argv如下

agrv[0] = "prog";
agrv[1] = "-d";
agrv[2] = "-o";
agrv[3] = "ofile";
agrv[4] = "data0";
agrv[5] = 0;

一定要记得可选实参从argv[1]开始,argv[0]保存程序的名字,而非用户输入。

含有可变形参的函数

有时我们无法预知应该向函数传递几个实参。
为了编写能处理不同数量实参的函数,C++11新标准提供了两种主要的方法。

如果所用的实参类型相同,可以传递一个名为initializer_list的标准库类型。
如果所用的实参类型不同,我们可以编写一种特殊的函数,也就是所谓的可变参数模版,这种方式会在以后介绍。

C++还有一种特殊的形参类型(即省略号),可以用它传递可变数量的实参。不过这种方法一般只用于与C函数交互的接口程序

initializer_list类型定义在同名的头文件中

initializer操作 含义
initializer_list<T> lst 默认初始化:T类型元素的空列表
initializer_list<T> lst{a, b, c…} lst元素数量和初始值一样多,lst的元素是对应初始值的副本,列表中的元素是const
lst2(lst) 拷贝或复制一个initializer_list对象不会拷贝列表中的元素;拷贝后原始列表和副本共享元素
lst2 = lst 拷贝或复制一个initializer_list对象不会拷贝列表中的元素;拷贝后原始列表和副本共享元素
lst.size() 列表中元素的个数
lst.begin() 返回指向lst中首个元素的指针
lst.end() 返回指向lst中尾元素的下一位置的指针

和vector一样,initailizer_list也是一种模版类型,定义时,必须说明列表中所含员的类型。
与vector不同的时,initializer_list对象中的元素永远是常量值,我们无法改变initializer_list对象中元素的值。

传递序列参数需要把序列放在花括号中

   error_msg({"funciton", expected, actual})

省略符形参

省略符行参时为了便于C++程序访问某些特殊的C代码而设置的,这些代码使用了名为varargs的C标准库。
省略符形参只能出现在形参列表的最后一个位置。

void foo(parm_list, ...);
void foo(...);

返回类型和return语句

return语句终止当前正在执行的函数并将控制权返回到调用该函数的地方。

无返回值的函数

没有返回值的return语句只能用在返回类型是void的函数中。返回void函数不要求非得有return语句。
如果在void函数中间位置加return;会提前退出,类似于break。

有返回值的函数

只要函数的返回类型不是void,则该函数内的每条return语句必须返回一个值。return语句返回值的类型必须与函数的类型相同,或者能隐式地转换成函数的返回类型。

值是如何被拷贝的

返回一个值的过程和初始化的过程类似,返回的值用于初始化调用点的一个临时量,该临时量就是函数调用的结果。

如函数返回string类型,返回值将拷贝到调用点,返回一个未命名的临时string对象。

不要返回局部对象的引用或指针

函数完成后,它所占用的存储空间也随之被释放掉。因此,函数终止意味着局部变量的引用将指向不再有效内存区域。

     const sting &manip(){string ret;if(!ret.empty()){return ret; //错误,返回局部对象的引用。}else{return "Empty"; //错误,“Empty”是一个局部临时变量。}}

调用一个返回引用的函数返回左值,其他返回类型得到右值。

主函数的返回值。

如果函数返回类型不是void,那么它必须返回一个值。但是也有例外:

我们允许主函数没有return语句直接结束,如果控制到达了main函数的结尾处而且没有return语句,编辑器将隐式插入一条返回0点return语句。

递归

如果一个函数调用了它自身,不过这种调用时直接的还是简介的,都称函数为递归函数。
在递归函数中,一定有某条路径是不包含递归调用的,否则,函数将“永远”递归下去,直到程序栈空间耗尽为止。我们有时候会说这种函数含有递归循环。

返回数组指针

因为数组不能被拷贝,所以函数不能返回数组。
不过函数可以返回数组的指针或者引用。

返回数组的指针或者引用的函数比较繁琐,但是有一些方法可以简化这一任务。如下:

     typedef int arrT[10];  // arrT是一个类型别名,他表示的类型是含有10个整数的数组。using arrT = int[10];  //等价于上述声明。arrT* func(int i);    //返回一个真相含有10个整数数组的指针。

如果不使用简化呢,如下:

    int (*func(int i))[10];

逐层解析如下:

  • func(int i)表示需要一个int类型的实参来调用函数。
  • (*func(int i))意味着我们可以对函数调用的结果执行解引用操作。
  • (*func(int i))[10]意味着解引func的调用将得到一个大小是10点数组。
  • int (*func(int i))[10] 表示数组中的元素是int类型。

使用尾置返回类型

C++11中可以使用尾置返回类型简化上诉声明

auto func(int i) -> int(*)[10]

使用decltype

还有一种情况,如果我们知道函数返回的指针将指向哪个数组,就可以使用decltype关键字声明返回类型。

int  odd[] = {1, 3, 5, 7, 9};
int even[] = {0, 2, 4, 6, 8};decltype(odd) *arrPtr(int i)
{return (i % 2) ? &odd : &even;//返回一个指向数组的指针。
}

函数重载

如果同一个作用域内的几个函数名字相同但是形参列表不同,我们称之为重载函数。

当调用这些函数时,编译器会根据传递的实参类型推断想要的是哪个函数。

不允许两个函数除了返回类型外其他所有的要素都相同。

重载和const形参

顶层const不影响传入函数的对象。
一个拥有顶层const的形参无法和另一个没有顶层const的形参区分开来。

      Record lookup(Phone);Record lookup(const Phone);    //重复声明了。Record lookup(Phone*);Record lookup(Phone* const)  //重复声明了。

如果形参是某种类型的指针或引用,则通过区分其指向的常量对象还是非常量对象可以实现函数重载。此时的const是底层的。

      Record lookup(Account&);Record lookup(const Account&); //新函数,作用于常量的指针。Record lookup(Account*);Record lookup(const Account*); //新函数,作用于指向常量的指针。

重载与作用域。

    string read();void print(const string &);void print(double);  void fooBar(int value){bool read = false;string s = read(); //错误,read是一个布尔值,而非函数//通常来说在局部作用域中声明函数不是一个好习惯void print(int);  //新作用域隐藏了之前的printprint("Valule:"); // 错误,print(const string &)被隐藏了print(ival);//正确print(3.14);//正确}

特殊用途的语言特性

默认实参

某些函数有这样一种形参,在函数的很多次调用中它们都被赋予一个相同的值,此时,我们把这个反复出现的值称为函数的默认实参。

含有默认实参的函数调用时,可以包含该实参,也可以省略该实参。

如,为窗口的高宽和字符背景都添加默认值。

 typedef string::size_type  sz;string screen(sz ht = 24, sz wid = 80, char backgrnd = ' ');

函数调用时实参按其位置解析,默认实参负责填补函数调用缺少的尾部实参。
例如,想要覆盖backgrnd默认值,需要为ht和sz提供实参。

函数声明时,一个形参只能被赋予一次默认实参,换句话说,函数的后续声明只能为之前那些没有默认值的形参添加默认实参。

局部变量不能作为默认实参。

用做默认实参的名字在函数声明所在的作用域内解析,而这些名字的求值过程发生在函数调用时:

   sz wd = 80;char def = ' ';sz ht();string screen(sz = ht(); sz = wd, char = def);void f2(){def = '*';sz wd = 100;window = screen();  // 调用 screen(ht(), 80, '*');}

内联函数和constexpr函数

把小规模的操作定义为函数有很多好处:

  • 容易阅读和理解
  • 确保行为统一
  • 可以统一修改
  • 可以反复利用
    但也有一些缺点:调用函数一般比求等价表达式的值要慢一些。
    在大多数机器上,一次函数调用其实包含着一系列工作:调用前要先保存寄存器,并在返回时恢复;可能需要拷贝实参;程序转向一个新的位置继续执行。

将函数指定为内联inline函数,通常就是将它在每个调用点上内联地展开。
如在调用

cout << shorterString(s1, s2) <<endl;

将在编译过程中展开成类似于下面的形式:

cout <<(s1.size() < s2.size() ? s1 : s2) <<endl;

从而消除函数在运行时的开销。
在函数的返回类型前加上inline就可以了。

一般来说,内联机制用于优化规模较小,流程直接,频繁调用的函数。

constexpr函数

constexpr函数是指能用于常量表达式的函数。
定义时有几点约定:函数的返回类型以及所有形参的类型都得是字面值类型,而且函数体中必须有且只有一条return语句
constexpr函数被隐式指定为内联函数。

我们允许constexpr函数的返回值并非一个常量

怎么理解呢?(引用自https://segmentfault.com/q/1010000004615565)

int main()
{   int x = 0;int z =  screen(x); //因为z是非constexpr的,不要求screen是constexpr的cout << z<<endl;return 0;
}
int main()
{   int x = 0;constexpr int z =  screen(x); //错误!! x的lifetime开始于screen(x)的外部cout << z<<endl;return 0;
}
int main()
{  constexpr int z =  screen(0); //screen(0)是常量表达式, 对于screen内部,x的lifetime开始于函数内部cout << z<<endl;return 0;
}

和其他函数不一样,内联函数和constexpr函数可以在程序中多次定义。基于这个原因,内联函数和constexpr函数通常定义在头文件中。

调试帮助

assert预处理宏

 assert(expr);

先对expr求值,如果表达式为假,assert输出信息并终止程序的执行。如果为真,什么都不做。
assert定义在cassert头文件中。
如对输入文本进行操作的程序可能要求给定单词的长度都大于某个阀值。

assert(word.size() > threshold);

NDEBUG预处理变量

assert的行为依赖于一个名为NDEBUG的预处理变量的状态。如果定义了NDEBUG,则assert什么也不做。
我们可以使用#define语句定义NDEBUG,从而关闭调试状态。

除了用于assert之外,也可以使用NDEBUG编写自己的条件调试代码。

    void print(const int ia[], size_t size){#ifndef NDEBUGcerr<<__func__<<":array size is"<<size<<endl;#endif//...

_ _ fun _ _ 输出当前调试的函数名字。
类型的还有
_ _ FLIE _ _ 存放文件名的字符串字面值
_ _ LINE _ _ 存放当前行号的整型字面值
_ _ TIME _ _ 存放文件编译时间的字符串字面值
_ _ DATE _ _ 存放文件编译日期的字符串字面值

函数匹配

函数匹配的第一步,选定本次调用对应的重载函数集,集合中的函数称为候选函数。
函数匹配的第二步,考察本次调用提供的实参,然后从候选函数中选出能被这种实参调用的函数,这些函数称为可行函数。
函数匹配的第三步,从可行函数中选择与本次调用最匹配的函数。

函数指针

函数指针指向的是函数而非对象。

和其他指针一样,函数指针指向某种特定类型。
函数的类型由它的返回类型和形参类型共同决定,与函数名无关。

如函数:

bool lengthCompare(const string &, const string &);

则声明指向该函数的指针。

bool (*pf)(const string&, const string&);

(*pf)的括号比不可少

当把函数名作为一个值使用时,该函数自动转换成指针
如:

  pf = lengthCompare;pf = &lengthCompare; //两者等价。

此外,我们还能直接使用指向函数的指针嗲用该函数,无须提前解引用指针。

bool b1 = pf("hello", "goodbye");
bool b2 = (*pf)("hello", "goodbye");
bool b3 = lengthCompare("hello", "goodbye"); //三者等价。

函数指针形参

和数组类型,虽然不能定义函数类型的形参,但是形参可以是指向函数的指针。此时,形参看起来是函数类型,实际上却是当成指针类型使用:

  void useBigger(const string &s1, const string &s2, bool pf(const string &, const string &));void useBigger(const string &s1, const string &s2, bool (*pf)(const string &, const string &)); //两者等价

如上所见,函数指针类型显得冗长而繁琐。我们可以使用类型别名和decltype来简化代码:

//函数类型
typedef bool Func(const string&, const string&);
typedef decltype(lengthCompare) Func2;//指向函数的指针
typedef bool (*FuncP)(const string&, const string&);
typedef decltype(lengthCompare) *FuncP2;

重新声明useBigger:

void userBigger(const string&, const string &, Func);
void userBigger(const string&, const string &, FuncP2);

和数组类似,虽然不能返回一个函数,但是可以返回一个指向函数的指针。

using F = int(int *, int); //F是函数类型,不知指针
using FF = int(*)(int *, int); //PF是指针类型PF f1(int);
F f1(int); //错误,不能返回一个函数
F *f1(int);

当然也可以如下声明:

int (*f1(int))(int *, int)

当然更好的方式是使用尾置返回类型的方式

auto f1(int) -> int (*)(int *, int)

C++笔记: 函数_Hammond‘s blog相关推荐

  1. 20171220-python学习笔记--函数类型

    20171220-python学习笔记--函数类型 备注: #位置参数 #传入两个参数 def power(x, n):s = 1while n > 0:n = n - 1s = s * xre ...

  2. 9_python笔记-函数

    9_python笔记-函数 练习1 写法1:flag标志位 写法2 写法3 写法4 知识点2 git bash 发出冲突 知识点3 列表的拷贝 b = a[:] 示例:列表的拷贝 知识点4 flag ...

  3. JavaScript学习笔记——函数 Part4:向函数传递函数、从函数返回函数(函数是一等公民)

    要点 函数是值,这个值就是函数引用 函数是一等公民:函数引用是一等值 可将函数引用赋给变量.含在数据结构(如对象)中.传递给其他函数或从其他函数返回 函数是一等公民 不要再认为函数是特殊的,有别于Ja ...

  4. C++笔记---函数声明(prototype)

    前言:这篇转载的文章是我很久以前写的,但是后来手机换号了,又注册新号开始继续写blog.旧文章不能合并到新账号,就以转载的形式纪念下过去 最近在看<C++ Primer Plus>,奈何买 ...

  5. Powershell学习笔记——函数和函数库

    前段时间公司封闭开发,就在封闭的前一天感冒发烧,为了封闭,一顿猛药下去,烧是退了,却在扁桃附近爆发出来--扁桃发炎加溃疡,搞了十多天才好啊,天天喝稀饭啊--所以请大家原谅这么久没有续上学习笔记.顺便: ...

  6. python全栈开发笔记---------函数

    一 数学定义的函数与python中的函数 初中数学函数定义:一般的,在一个变化过程中,如果有两个变量x和y,并且对于x的每一个确定的值,y都有唯一确定的值与其对应,那么我们就把x称为自变量,把y称为因 ...

  7. C语言工作笔记-函数指针的使用(补充C回调系统)

    本篇博文是基于: https://blog.csdn.net/qq78442761/article/details/89202337 这篇博文的代码! 这里主要是做两个补充! 1. 模块一想加入一个处 ...

  8. Javascript 学习笔记 - 函数 - 关于IIFE - 关于函数声明和函数表达式 - 个人总结

    一切起源于一段代码(近来学完java基础 开始学习敲一下javascript): var getter = function(){var dayNames=["Sunday",&q ...

  9. 《流畅的Python第二版》读书笔记——函数作为一等对象

    引言 这是<流畅的Python第二版>抢先版的读书笔记.Python版本暂时用的是python3.10.为了使开发更简单.快捷,本文使用了JupyterLab. 函数是Python的一等( ...

最新文章

  1. React全家桶环境搭建过程
  2. Apache应用实例:建立yum服务器
  3. php-fpm启动后没有监听端口9000
  4. 【LeetCode笔记】399. 除法求值(Java、图)
  5. raspberry pi_Raspberry Pi,CNC铣削,WTF,Cypht,HomeBank,Wekan等的使用方法
  6. 罗永浩直播间再回应直播售假:全方位整改 成立质控实验室
  7. 如何将自己的代码发布到Maven中央仓库?
  8. SLAM无人车通过上摄像头扫描二维码重定位
  9. 一文读懂人工智能、机器学习、深度学习、数据挖掘、模式识别、计算机视觉、大数据是什么和它们之间的关系!深度好文!重磅推荐!
  10. opencv 0x00007FF986D04ED9 处(位于 ConsoleApplication2.exe 中)有未经处理的异常: Microsoft C++ 异常: cv::Exception
  11. 泛娱乐出海走出水土不服,元宇宙社交诞生新机会!
  12. wago edz 下载_用电子枪制造的WeakAuras Wago.io桥
  13. Mose机器翻译Ubuntu18配置和遇到的问题
  14. java的excel模板下载(解决中文名乱码问题)
  15. Kali linux最新2018年安装Netspeed
  16. 贵有恒,何必三更眠五更起;最无益,莫过一日暴十日寒。
  17. wms仓库管理系统带来的效益
  18. C++实现栈的基本操作(入栈,出栈,取栈顶)
  19. matlab经纬度画轨迹图_MATLAB将经纬度坐标转换成直角坐标
  20. 已安装更新版本的onedrive_微软 OneDrive 阻止部分用户升级 Win10 版本 2004 正式版...

热门文章

  1. Java程序员应该具备的辅助开发神器
  2. RK3568-B2-ANDROID11-WIFI-RTL8821CU
  3. Transfer Learning 迁移学习的相关知识
  4. 电影《小萝莉的猴神大叔》观后感
  5. python中回车用什么表示_解释stdscr中的“ENTER”键(Python中的curses模块)
  6. Elasticsearch7.x证书过期简单解决方法
  7. Mybatis Plus基础06 mapperLocations配置(指定Mapper.xml文件路径)
  8. 有声语音计算机软件,有声语音计算器
  9. TIM/QQ——将群文件中的临时文件转换成永久文件的方法
  10. 大数据编程语言 Scala 进阶篇