《C++ Primer 》第三十九天 新篇章

C++提供了新的函数特性(这些特性C中没有)

内联函数

引用

按引用传参

默认参数

函数重载

函数模板

函数模板具体化

内联函数是为提高程序运行速度而提出的。(这是对C的改进)。

常规函数和内联函数编写方式相同,但C++编译器将它们与程序整合的方式是不同的。(因此要了解内联函数与常规函数的区别,必须深入到程序内部)

编译的最终产品是一个可执行的程序(这个程序由二进制的机器语言组成,可直接在机器上运行)。

在进行常规函数调用时,会将函数的参数复制到堆栈,并执行函数代码。(并且这个工程中,会进行多次内存的跳转,来实现主程序和调用函数之间的切换,这会有一定的开销。而对于内联函数,编译器直接将函数源码加入到主程序中,这样在程序执行的时候,就不会有内存的跳转,从而加快了程序运行的时间——但这肯定需要更多的内存,因为这相当于直接把源码赋值了过来,就是说只要有调用内联函数的地方,编译器就回用内联函数的源码替换内联函数。所以要有选择的使用内联函数,如果程序执行代码的时间比 函数调用耗费的时间长,那么使用内联函数不会对程序时间有太大的提升;但是反之,则可以 考虑使用内联函数,但是提升的性能也是有限的——如果函数被调用的次数很多,那么性能提升会很明显)。

在普通函数的 函数定义(和函数原型)之前加上 inline 关键字,那么该函数就被转换为了内联函数。(如果函数过大,或者 函数是递归的 则不考虑将其转换为内联函数。一般情况下,直接将函数定义在之前书写函数原型的位置,并加上inline关键字——也就是说,去掉函数原型,只保留函数定义,并且把函数定义提前到 之前函数原型所在的位置。)

内联函数和普通函数一样,都是按值来传递参数的。(这使得 C++的内联函数功能 ,优于 C语言的宏定义。C语言中使用 #define来实现宏定义,宏定义可以实现了内联函数相同的功能,但是宏不是通过传递参数来实现的,而是基于文本的直接替换来实现的,这使得宏编写时要求较严格。因此最好的方式,使用C++的内联函数来代替C语言的宏——实现函数功能的宏)

引用常用与函数传参(尤其是 结构 和 对象 向函数进行参数传递的时候)。(应用对函数 处理大型结构非常有用,并且在类的设计中也经常用到)

&符号 在C++/C 中用来只是变量的地址。(但是在C++中 赋予了&符号 另一个含义——用来声明引用,并且在声明引用的同时必须对其进行初始化,也就是必须声明的同时进行赋值,这一点不同于指针;并且引用本质相当于 const指针,一旦赋值便不会在改变,也无法人工的改变它,它就相当于变量本身其实。举例: int rats; int & rodents=rats; 第二个语句就声明了一个引用——rodents为rats的别名  ,这里的&不是地址运算符,而是作为类型标识符的一部分, int & 的含义是 声明一个 指向 int变量的 引用。在例子中 rats和rodents 指向相同的内存单元)

通过传递引用的方式,实现函数的参数传递,称为按引用传递(C语言中只有按值传递——指针本身也是 按值传递,传递是指针的地址,C++中有按值传递和按引用传递两种方式)

函数 引用传参 语法:void swapr(int & a,int &b)。(在将实参传递给形参的时候,相当于 声明了引用,同时对引用进行初始化。如果不希望对引用所指向的内存进行修改,可以使用const关键字,增加const关键字后的语法为:void swapr(const int & a, const int & b)。这种不希望对原值修改的情况一般使用按值传递即可,但是对于 结构或类 这些数据量比较大的类型,使用 const引用将能够极大地节省 创建副本带来的开销。当对函数进行参数传递的时候,按值传递,可以传递 表达式、常量、变量等;而 按引用传递,则实参必须是 变量才行,如果传递其他形式的参数,编译器报错——但是 当形参是 const引用时,允许 向函数传递 其他形式的实参 ,这时底层是通过生成临时变量的形式来接受 其他形式的实参的值,最终生成的是这个临时变量的引用,并且对这个引用的操作不会影响到原来的值,因为这个引用是对临时变量的引用,这种引用效果上其实等同于按值传参。在按 const引用传参的时候,如果传递给函数的 实参不是左值 或者 和const 形参的类型不匹配,这时,C++将创建 和形参类型一致的 匿名的临时变量 ,并将实参进行类型转换后 赋值给临时变量,最终对这个临时变量 进行引用—这些临时变量 只在函数调用期间存在,函数使用结束后 编译器便会将这些临时变量删除 )

所有可以被引用 的数据对象 被称为左值 (如 变量 数组元素 结构成员 指针等)。(常量——字符常量除外、表达式 就不属于左值)

使用const引用的优势:防止错误的修改原数据;const引用 可以同时 接受  const和非const实参——非const引用,只能接受 非cosnt实参;const引用使函数能根据情况生成临时变量,来接受右值数据

针对右值数据,C++新增了右值引用——右值引用使用的是 && 符号来声明,语法为:double && jref=3*a+b;。(右值引用 主要是 供 库设计人员使用,比如 实现移动语义等功能)

函数在返回结果的时候,也分为 按值返回和按引用返回。(按值返回,也相当于返回的是 结果的副本。返回引用,则是返回 结果的 别名)

声明指针时 会隐式的调用new 来分配内存。(auto_ptr模板  和 unique_ptr 可实现自动释放 new出来的内存)

一个类传递个另一个类 这称为类的继承。(前者是基类,后者是派生类。派生类继承了基类的方法。并且 基类的引用 同时也是派生类的引用)

对于基本的数据类型 cin使用的是引用。(例如 直接写成  cin>>n; 而不用写成 cin>>&n )

函数的默认参数 也是C++相对于C新增加的功能。(如果想使用默认参数,则必须 并且 执须 在函数原型中进行设置——不需要在函数定义中设置,并且在调用函数时,必须对形参一次赋值——中间不能间隔,比如 harpo(3, ,8);这个语句就是错误的,因为中间间隔了一个参数。通过使用默认参数,可以减少要定义的析构函数的数量 、方法 以及 方法重载的数量)

函数重载(也称为多态,意思就是允许函数有种形式——也就是 允许多个同名函数,这几个同名函数的参数列表不同;这多个同名函数相当于对名称进行了重载,所以这种语法形式也被称为函数虫重载。)也是C++ 相对C 新增加的功能。

函数重载的时候,允许出现 函数返回值类型不同 ,同时参数类表也不同的情况,也允许只有参数列表不同,但是不允许 只有数返回值类型不同——而参数列表完全相同。

默认参数的使用,可以在一定程度上代替一部分的函数重载。(默认参数 本质上 是一种特殊的函数重载)

C++底层,会将函数的 类型名等 按照一定的格式进行加密——这称为 名称修饰(或名称矫正)(也就是 重新编码——用指定的字符进行替换内容,程序员是看不到的,这种编码只是程序底层的一些操作)。

函数模板 是使用 泛型来定义函数(可以通过将 类型作为参数传递给模板——这种将类型作为参数的形式 被称为 参数化类型,从而 通过编译器 生成 具体类型的函数)。(函数模板使得 可以以泛型的方式编写程序——这种编写程序的方式成为通用编程)。

创建函数模板,必须同时以相同的语法 提供函数原型 和 函数定义 (并且,调用函数模板的时候,编译器会根据 传入参数的类型,来自动的生成对应类型的函数——这个过程是隐式的、自动的,不需要额外的定义。)。函数模板的语法为:

template <typename AnyType>

void Swap(AnyType &a ,AnyType &b){  AnyType temp;temp=a; a=b; b=temp;}   (创建函数模板时,关键字 类型名 尖括号 这些元素都是必须的。其中的typename  也可以 class  ,这两个关键字在这里都可以用)

通常将 函数模板 在头文件中进行创建。(并且,编译器最终生成的代码,只包含根据模板创建的 针对具体类型的 函数,而不包含原来的模板函数)

模板函数可以像普通函数一样 实现函数的重载,并且在模板函数的参数类表中 ,也可以出现 确定类型的参数 (比如 int型等)

对于一个函数名,可以有 普通函数、模板函数、显示具体画的模板函数、以及这三种类型的函数重载。(三种类型函数的有限顺序依次是   普通函数>具体模板函数>模板函数。其中具体模板函数的语法为  template <> void Swap<job>(job & ,job &);  该语句中的 <job> 是可有可无的)

C++中也可以显示的定义 模板要生成的具体类型的函数——这被称为函数的显示实例化。(只需提供 该类型的函数原型即可,函数原型的语法为 template void Swap<int>(int,int);  )

在调用函数模板的时候,也可以 进行实例化的定义 语法为(cout <<Add<double>(x,m)<<endl;)

不能再同一个文件中使用  同一种函数类型的 显示实例化 和显示具体化。

在函数 传参的过程中, 无法实现 普通类型变量 向指针类型的自动转化 (这种转换 需要 人工 进行强制转换)

函数调用时 ,如果遇到多个匹配的原型或模板,则优先选择  非模板的函数 、更加具体的函数——如果出现多个函数的 匹配程度一致 编译器则无法区分 会报错。(在函数调用时 也可以 显示的指定 使用模板 或者 使用具体类型的模板。语法为:cout << lesser<>(m,n) <<endl; 该语句中的 <> 含义是 使用模板函数,而不适用常规函数。cout<<lesser<int>(x,y)<<endl; 该语句中的 <int> 含义是  使用模板函数 并将其 实例化为 int类型的函数。)

对于参数列表 为多个 参数的 函数,匹配时,最佳函数,必须是每个参数 的匹配程度  都不差于 其他函数的匹配,并且至少有一个参数的匹配优于其他参数。

在模板功能 刚开始添加进c++的时候,人们没有意识到 模板函数 和 模板类会这么有用。但是随着程序员们 不断探索 模板使用的 各种可能性——并提出修改建议,采用了现在的C++11 中 较为 完善的模板功能。


C++11 中提出了 decltype 关键字,该关键字用于模板中——指定 变量的类型。decltype的语法为:decltype(x) s; 该语句的含义是  定义一个变量 s,该变量的类型和 x的类型一致。(x 可以是 具体类型声明出来的变量 、可以是 一个表达式 、可以是一个函数调用 等等。当x 是函数调用的时候,代表 s的类型为  函数的返回类型,这个判断过程,只是编译器根据函数原型来实现的,其实并不需要真正的调用函数——虽然语法上 写的是 函数调用)

double xx=4.4

decltype ((xx)) r2=xx; 该语句表示的是 r2 xx的引用。(也就是说 r2的类型是  double  &——(())两个括号 就代表了 r2 是引用类型)

decltype(xx) r2==xx;该语句表示的是 r2 是 xx的副本。(也就是说 如r2的类型是  double)

当需要对模板  的函数返回类型 使用 decltype时,不能直接将其加载函数名之前。(因为,decltype 需要用到函数内部一些变量,但是,在未进入函数之前,这些变量是不存在的。因此 C++ 提出了 后置返回类型的概念,也就是说,在函数的末尾来进行函数类型的定义。语法为 :

template<class T1, class T2>

auto gt(T1 x, T2 y) -> decltype(x+y)   {;;;return x+y;} 。(这定义形式中,decltype 在 x,y变量声明语句之后,所有可以使用 x+y 来进行 函数返回类型的设置)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,997评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,603评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,359评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,309评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,346评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,258评论 1 300
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,122评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,970评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,403评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,596评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,769评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,464评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,075评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,705评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,848评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,831评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,678评论 2 354

推荐阅读更多精彩内容