Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >C++学习笔记3[通俗易懂]

C++学习笔记3[通俗易懂]

作者头像
全栈程序员站长
发布于 2022-07-07 13:02:21
发布于 2022-07-07 13:02:21
27900
代码可运行
举报
运行总次数:0
代码可运行

大家好,又见面了,我是全栈君。

函数小结 :

函数是有名字的计算单元,对程序(就算是小程序)的结构化至关重要。

函数的定义由返回类型、函数名、形參表(可能为空)以及函数体组成。函数体是调用函数时运行的语句块。

在调用函数时,传递给函数的实參必须与对应的形參类型兼容。

给函数传递实參遵循变量初始化的规则。非引用类型的形參以对应实參的副本初始化。对(非引用)形參的不论什么改动仅作用于局部副本。并不影响实參本身。

复制庞大而复杂的值有昂贵的开销。

为了避免传递副本的开销。可将形參指定为引用类型。对引用形參的不论什么改动会直接影响实參本身。应将不须要改动对应实參的引用形參定义为const 引用。

在 C++ 中。函数能够重载。

仅仅要函数中形參的个数或类型不同,则同一个函数名可用于定义不同的函数。编译器将依据函数调用时的实參确定调用哪一个函数。

在重载函数集合中选择适合的函数的过程称为函数匹配。

C++ 提供了两种特殊的函数:内联函数和成员函数。将函数指定为内联是建议编译器在调用点直接把函数代码展开。

内联函数避免了调用函数的代价。成员函数则是身为类成员的函数。

1. 函数不能返回还有一个函数或者内置数组类型。但能够返回指向函数的指针,或指向数组元素的指针的指针:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 // ok: pointer tofirst element of the array
 int *foo_bar() { /*... */ }
 //在定义或声明函数时。没有显式指定返回类型是不合法的:
 // error: missingreturn type
 test(double v1,double v2) { /* ... */

2.函数形參表

函数形參表能够为空,但不能省略。没有不论什么形參的函数能够用空形參表或含有单个keywordvoid 的形參表来表示。比如,以下关于process 的声明是等价的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 void process() { /*... */ }     // implicit void parameter list 
 void process(void){/* ... */ }  // equivalent declaration

形參表由一系列用逗号分隔的參数类型和(可选的)參数名组成。

假设两个參数

具有同样的类型,则其类型必须反复声明:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 int manip(int v1, v2){ /* ... */ }      // error
 int manip(int v1, intv2) { /* ... */ }  // ok

參数表中不能出现同名的參数。类似地,局部于函数的变量也不能使用与函数的随意參数同样的名字。參数名是可选的,但在函数定义中,通常全部參数都要命名。

參数必须在命名后才干使用。

3. 參数传递

每次调用函数时,都会又一次创建该函数全部的形參,此时所传递的实參将会初始化相应的形參。 形參的初始化与变量的初始化一样:假设形參具有非引用类型,则复制实參的值,假设形參为引用类型,则它仅仅是实參的别名。

4. 复制实參的局限性

复制实參并非在全部的情况下都适合,不适宜复制实參的情况包含:

• 当须要在函数中改动实參的值时。

• 当须要以大型对象作为实參传递时。对实际的应用而言。复制对象所付出的时间和存储空间代价往往过在。

• 当没有办法实现对象的复制时。

5. 更灵活的指向const 的引用

假设函数具有普通的非const 引用形參,则显然不能通过const 对象进行调用。毕竟。此时函数能够改动传递进来的对象,这样就违背了实參的const 特性。但比較easy忽略的是,调用这种函数时。传递一个右值或具有须要转换的类型的对象相同是不同意的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// function takes anon-const reference parameter
 int incr(int &val)
 {
 return ++val;
 }
 int main()
 {
 short v1 = 0;
 const int v2 = 42;
 int v3 = incr(v1);                 // error: v1 is not an int
 v3 = incr(v2);                     // error: v2 is const
 v3 = incr(0);                      // error: literals arenot lvalues
 v3 = incr(v1 + v2);                // error: addition doesn't yield anlvalue
 int v4 = incr(v3);                 // ok: v3 is a non const objecttype int
 }

6. 传递指向指针的引用 –指针的交换

如果我们想编写一个与前面交换两个整数的swap 类似的函数,实现两个指针的交换。已知需用* 定义指针。用& 定义引用。

如今,问题在于怎样将这两个操作符结合起来以获得指向指针的引用。这里给出一个样例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 // swap values of twopointers to int
 void ptrswap(int*&v1, int *&v2)
 {
 int *tmp = v2;
 v2 = v1;
 v1 = tmp;
 }

形參 int *&v1的定义应从右至左理解:v1是一个引用,与指向int 型对象的指针相关联。也就是说,v1仅仅是传递进ptrswap 函数的随意指针的别名。重写第7.2.2 节的main 函数,调用ptrswap 交换分别指向值10 和20 的指针:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 int main()
 {
 int i = 10;
 int j = 20;
 int *pi = &i; //pi points to i
 int *pj = &j; //pj points to j
 cout <<"Before ptrswap():\t*pi: " << *pi <<"\t*pj: " << *pj << endl;
 ptrswap(pi, pj); //now pi points to j; pj points to i
 cout <<"After ptrswap():\t*pi: "<< *pi << "\t*pj: " << *pj<< endl;
 return 0;
 }
 
 // 编译并运行后,该程序产生例如以下结果:
 Before ptrswap():*pi: 10 *pj: 20
 After ptrswap(): *pi:20 *pj: 10

7. 千万不要返回局部对象的引用

理解返回引用至关重要的是:千万不能返回局部变量的引用。

当函数运行完成时。将释放分配给局部对象的存储空间。

此时,对局部对象的引用就会指向不确定的内存。考虑以下的程序:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 // Disaster: Functionreturns a reference to a local object
 const string&manip(const string& s)
 {
 string ret = s;
 // transform ret insome way
 return ret; // Wrong:Returning reference to a local object!
 }

这个函数会在执行时出错,由于它返回了局部对象的引用。当函数执行完成,

字符串ret 占用的储存空间被释放,函数返回值指向了对于这个程序来说不再有效的内存空间。

8. 千万不要返回指向局部对象的指针

函数的返回类型能够是大多数类型。特别地。函数也能够返回指针类型。和返回局部对象的引用一样,返回指向局部对象的指针也是错误的。一旦函数结束,局部对象被释放。返回的指针就变成了指向不再存在的对象的悬垂指针.

9. 内联函数

调用函数比求解等价表达式要慢得多。在大多数的机器上。调用函数都要做非常多工作;调用前要先保存寄存器,并在返回时恢复;复制实參;程序还必须转向一个新位置运行。

将函数指定为inline 函数,(通常)就是将它在程序中每一个调用点上“内联地”展开。

如果我们将shorterString 定义为内联函数。则调用:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
cout <<shorterString(s1, s2) << endl;

在编译时将展开为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 cout <<(s1.size() < s2.size() ? s1 : s2)  << endl;

从而消除了把shorterString 写成函数的额外运行开销。

从而消除了把shorterString 写成函数的额外运行开销。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 // inline version:find longer of two strings  inline conststring &
 shorterString(conststring &s1, const string &s2)
 {
   return s1.size() <s2.size() ? s1 : s2;
 }  

inline 说明对于编译器来说仅仅是一个建议,编译器能够选择忽略这个。

一般来说,内联机制适用于优化小的、仅仅有几行的并且常常被调用的函数。大多数的编译器都不支持递归函数的内联。

一个1200 行的函数也不太可能在调用点内联展开。

内联函数应该在头文件里定义,这一点不同于其它函数。

10. 重载与作用域

一般的作用域规则相同适用于重载函数名。

假设局部地声明一个函数,则该函数将屏蔽而不是重载在外层作用域中声明的同名函数。由此推论。每个版本号的重载函数都应在同一个作用域中声明。

一般来说,局部地声明函数是一种不明智的选择。函数的声明应放在头文件里。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/* Program for illustration purposes only:
 * It is bad style fora function to define a local variable
 * with the same nameas a global name it wants to use
 */
 string init();                    // the name init hasglobal scope
 void fcn()
 {
 int init = 0;                     // init is local andhides global init
 string s = init();                // error: global init is hidden
 }void print(const string &);
 void print(double);               // overloads the print function
 void fooBar(int ival)
 {
 void print(int);                  // new scope: hides previousinstances ofprint
 print("Value:");                  // error:print(const string &) is hidden
 print(ival);                      //ok: print(int) is visible
 print(3.14);                      //ok: calls print(int); print(double) is hidden
 }

11. 候选函数

调用所考虑的重载函数集合,该集合中的函数称为候选函数。候选函数是与被调函数同名的函数,

可行函数

从候选函数中选择一个或多个函数。它们可以用该调用中指定的实參来调用。

因此,选出来的函数称为可行函数.

12. 重载和const 形參

可基于函数的引用形參是指向const 对象还是指向非const 对象,实现函数重载。将引用形參定义为const 来重载函数是合法的,由于编译器能够依据实參是否为const 确定调用哪一个函数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 Recordlookup(Account&);
 Record lookup(constAccount&); // new function
 const Account a(0);
 Account b;
 lookup(a);          // calls lookup(const Account&)
 lookup(b);          // calls lookup(Account&)

假设形參是普通的引用。则不能将const 对象传递给这个形參。假设传递了const 对象。则仅仅有带const 引用形參的版本号才是该调用的可行函数。

13. 指向函数的指针

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

14.函数指针

函数指针类型相当地冗长。使用typedef 为指针类型定义同义词,可将函数指针的使用大大简化:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 typedef bool(*cmpFcn)(const string &, const string &);

在引用函数名但又没有调用该函数时,函数名将被自己主动解释为指向函数的指针。

如果有函数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 // compares lengths of two strings
 boollengthCompare(const string &, const string &);

除了用作函数调用的左操作数以外,对lengthCompare 的不论什么使用都被解释为例如以下类型的指针:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 bool (*)(const string&, const string &);
 // 可使用函数名对函数指针做初始化或赋值:
 cmpFcn pf1 = 0;                        // ok: unboundpointer to function
 cmpFcn pf2 =lengthCompare;             // ok: pointer typematches function's type
 pf1 = lengthCompare;                   // ok: pointer type matchesfunction's type
 pf2 = pf1;                             // ok: pointer types match
 
 // 此时。直接引用函数名等效于在函数名上应用取地址操作符:
 cmpFcn pf1 =lengthCompare;
 cmpFcn pf2 =&lengthCompare;

函数指针仅仅能通过同类型的函数或函数指针或0 值常量表达式进行初始化或赋值。将函数指针初始化为0,表示该指针不指向不论什么函数。指向不同函数类型的指针之间不存在转换:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 string::size_typesumLength(const string&, const string&);
 boolcstringCompare(char*, char*);
 // pointer tofunction returning bool taking two const string&  cmpFcn pf;
 pf = sumLength;                          // error: returntype differs
 pf = cstringCompare;                     // error: parameter typesdiffer
 pf = lengthCompare;                      // ok: function and pointertypes match exactly

15. 通过指针调用函数

指向函数的指针可用于调用它所指向的函数。能够不须要使用解引用操作符,直接通过指针调用函数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 cmpFcn pf =lengthCompare;
 lengthCompare("hi","bye");     // direct call
 pf("hi","bye");                // equivalent call: pf1 implicitly dereferenced
 (*pf)("hi","bye");             // equivalent call: pf1 explicitly dereferenced

假设指向函数的指针没有初始化,或者具有0 值。则该指针不能在函数调用中使用。

仅仅有当指针已经初始化,或被赋值为指向某个函数,方能安全地用来调用函数。

16. 指向重载函数的指针

C++ 语言同意使用函数指针指向重载的函数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 extern void ff(vector<double>);
 extern void ff(unsigned int);
 
 // which functiondoes pf1 refer to?
 void (*pf1)(unsignedint) = &ff; // ff(unsigned)
 //指针的类型必须与重载函数的一个版本号精确匹配。假设没有精确匹配的函数,则对该指针的初始化或赋值都将导致编译错误:
 // error: no match:invalid parameter list
 void (*pf2)(int) =&ff;
 
 // error: no match:invalid return type
 double(*pf3)(vector<double>);
 pf3 = &ff;

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/116217.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年1月2,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
C++の函数——内联函数&函数指针
我们先看一下内联函数。内联函数也是C++中的一个重要特性。所谓内联函数,其实本质上也是一种函数,在形式上的表现就是在普通函数前面加上关键字"inline",然后相对于普通函数来说,它也比较短小。C++中"inline"的作用其实是为了优化代码的运行,降低代码的执行时间,就像在C语言中的宏函数一样,作用也是为了降低代码的执行时间。
leoay
2020/01/14
2.6K0
《C++Primer》第六章 函数
函数体是一个语句块,形参和函数体内部定义的变量统称为局部变量local variable,仅在函数的作用域内可见,同时局部变量还会隐藏hide在外层作用域中同名的其他声明中。
TOMOCAT
2020/12/02
7670
c++函数指针相关知识点详细总结!!!
函数指针初识 函数指针指向的是函数而非对象。 和其他指针一样,函数指针指向某种特定类型。 函数的类型由它的返回类型和形参类型共同决定。 例如: //比较两个string对象的长度 bool lengthCompare(const string& s1,const string& s2); 该函数的类型是 bool(const string&,const string&). 要想声明一个可以指向该函数的指针,只需要用指针替换函数名即可: //pf指向一个函数,该函数的两个参数是const string的引用
大忽悠爱学习
2021/11/15
3110
c++基础之函数
距离上次更新又过了一周,又该更新新的读书笔记了。本次更新的主要是c++中函数部分的内容
Masimaro
2021/03/11
5900
C++:17---函数指针
一、格式 指针名前*号,并且将*和指针名用括号括起来 例如: //指针名为pf,指向一个返回值为bool,参数为两个const string&的函数bool (*pf)(const string&, const string&);//这个不是函数指针,而是一个返回值为bool*的pf函数bool *pf(const string&, const string&); 二、函数指针的赋值 可以直接将函数名赋值给函数指针,或者在函数名前加&符号都可以 bool lengthCompare(const strin
用户3479834
2021/02/03
1K1
c++模板与泛型编程
编译器用推断出的模板参数来为我们实例化(instantiate)一个特定版本的函数,生成的版本称为模板的实例(instantiation)。
梦飞
2022/06/23
6740
第6章 函数
第6章 函数 ---- 第6章 函数 6.1 函数基础 6.2 参数传递 6.3 返回类型和 return语句 6.4 函数重载 6.5 特殊用途语言特性 6.6 函数匹配 6.7 函数指针 ---
用户1653704
2018/06/07
1.3K0
C++高级主题系列篇
函数 A 在执行过程中发现异常时可以不加处理,而只是“拋出一个异常”给 A 的调用者,假定为函数 B。
用户9831583
2022/06/16
4960
C++高级主题系列篇
C++ 知识点总结篇
const 在不同位置时的不同意义 指针类型前:声明一个指向常量的指针,程序中不能通过指针来改变它所指向的值,但指针本身的值可以改变,即指针可以指向其他数据; "*"号和指针名之间,声明一个指针常量(常指针),指针本身的值不可改变,即不能指向其他数据,但指向的数据的值可以改变; 两个地方都加,声明指向常量的指针常量,指针本身的值不可改变,指向的数据也不能通过指针改变; 函数指针 使用函数指针之前,必须先赋值,使它指向一个函数入口地址,赋值语法格式为:函数指针名 = 函数名,其中函数名代表的函数必须是一个已经
村雨遥
2022/06/15
5280
C++ 知识点总结篇
【笔记】《C++Primer》—— 第6章:函数
函数这一节内容又多又杂,但是相当有用,尤其是其中关于引用的应用和最后的调试部分。可能会比较长,等下一节写完就来做个小总结。
ZifengHuang
2020/07/29
7520
【笔记】《C++Primer》—— 第6章:函数
C++ Primer ---函数(读书笔记)
一个函数是由 返回类型 函数名称 0个或多个形参以及函数体构成。 函数调用时 使用函数名称加小括号,小括号里面是实参。 函数调用时,完成部分的工作:
HeaiKun
2020/07/07
6530
c++从入门到进阶--引用与常量
constexpr必须用常量表达式初始化,也就是说必须在编译过程就能计算出结果(若要用函数作为constexpr的初始值那么该函数应该是constexpr类型的函数)。
风骨散人Chiam
2020/10/28
8380
C语言到C++的OOP 面向对象编程
1、全面兼容C,C的许多代码不经修改就可以为Cpp所用,用C编写的库函数和实用软件可以用于Cpp。
小林C语言
2020/12/21
3.3K0
C语言到C++的OOP 面向对象编程
第 19 章 特殊工具与技术
将这篇文章在作业部落中的链接放置于此,对格式有轻微强迫的童鞋,请移步这里。 第 19 章 特殊工具与技术 标签: C++Primer 学习记录 运行时类型识别 枚举类型 类成员指针 ---- 第 19 章 特殊工具与技术 19.1 控制内存分配 19.2 运行时类型识别 19.3 枚举类型 19.4 类成员指针 19.5 嵌套类 19.6 union:一种节省空间的类 19.7 局部类 19.8 固有的不可移植的特性 ---- 19.1 控制内存分配 当使用一条 new表达式时string *sp =
用户1653704
2018/06/07
8830
【c语言】指针就该这么学(3)
在c语言中,不仅有变量的指针,也有函数指针。与变量相同,函数指针存放的是函数的地址,通过函数的地址可以调用该函数。
ephemerals__
2024/10/24
1630
【c语言】指针就该这么学(3)
初识C++ · 类和对象(中)(2)
前言:上篇文章已经介绍了6个默认成员函数中的3个函数,分别是构造函数,析构函数,拷贝构造函数,本文介绍的是后三个,赋值运算符重载,const成员函数,取地址操纵符重载。
_lazy
2024/10/16
1070
初识C++ · 类和对象(中)(2)
C++关键知识点梳理
类似于函数,但是其()中的参数不是真的函数参数,在编译器进行宏展开时对()里的参数进行"一对一"的替换。
liddytang
2023/03/08
1K0
深入浅出C/C++函数指针
和变量一样,函数在内存中有固定的地址,函数的实质也是内存中一块固定的空间。函数的地址存放其机器代码的内存的开始地址。当我们需要调用一个函数并让其使用我们期望的函数进行操作时,函数指针就能发挥作用了。比如pthread_create函数,需要自定义线程的轨迹。指定线程函数的指针,新线程将从该函数的起始地址开始执行。
Andromeda
2023/11/22
2900
第 18 章 用于大型程序的工具
本文应该是在年前写完的,结果由于要回家参加同学婚礼,走的太过匆忙,所以年后回到学校才写完。在写本篇博客时,我尝试使用了 PC版的讯飞输入法,直接可以将大段的文字通过语音的方式码进来,写作效率唰唰的提高。另外,有些书中的代码也比较长,敲起来也比较费时费力。这是使用在线文字识别来导入的,可以转换成带有格式的 Word文档,从而在复制粘贴到 MarkDown中,之后再调整下格式后就 OK了。我还是觉得作业部落的排版更好看一点,所以这里也把本文在作业部落的链接也放在这里了。外貌协会的同学可以点击这里。 第 18 章
用户1653704
2018/06/07
1.1K0
【C语言】指针总结3
注:代码 const char pstr = “hello.”; 特别容易让人以为是把字符串 hello 放 到字符指针 pstr 里了,但是本质是把字符串 hello. 首字符的地址放到了pstr中。*
用户11290673
2024/09/25
900
【C语言】指针总结3
相关推荐
C++の函数——内联函数&函数指针
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验