第八章 函数幽探

内联与宏:

C++新增的内联函数与普通函数一样是按值传递的,而宏是直接替换的。

#define SQUARE(X) X*X
int a;
a = SQUARE(5+10) //相当于a = 5+10*5+10

C++的引用变量:

引用变量的最大用途是用作函数的形参,通过将引用变量作为参数,函数将使用原始数据而不是其副本。引用为处理大型结构提供了非常方便的途径。

将引用作为函数参数的参数传递方法称为按引用传递。

传递引用的限制更严格,引用只是得到了变量的别名,此时将不能传递表达式。

临时变量、引用参数和const

如果实参和引用参数不匹配,C++将生成临时变量。但是目前,仅当参数为const引用时,C++才允许这么做(以前不一样)。

下面两种情况将生成临时变量:

1. 参数的类型正确,但不是左值。

2. 参数的类型不正确但可以转换成正确的类型。

为什么要生成临时变量?

如果接受引用参数的函数的意图是修改作为参数传递的变量,那么创建临时变量将阻止这种意图的实现,其行为类似于按值传递;

如果接受引用参数的函数的目的只是使用传递的值,而不是修改他们,因此临时变量不会造成任何不利的影响,反而会使函数在可处理的参数种类方面更通用。

应尽可能将引用声明为const:

1. 使用const可以避免无意中修改数据的编程错误;

2. 使用const使函数能够处理const和非const实参,否则将只能接受非const数据;

3. 使用const引用,使函数能够正确生成并使用临时变量。

正常情况下接受引用参数的函数的实参是左值,若不是左值,但实参类型正确且为const引用的话,将生成临时变量。

C++11新增了另一种引用,右值引用,是使用&&声明的(把以前的引用称为左值引用):

double j = 15.0;
double && jref = 2.0*j + 18.5; //不能使用double &声明jref

使用引用的主要目的是应用与结构和类的,而不是基本的内置类型。

将引用用于结构体

返回引用时,应避免引用函数终止时不再存在的内存单元(例如,返回临时变量的引用)。

函数返回结构体引用时,函数调用可以作为左值被赋值;为避免函数调用作为左值被赋值(防止返回的内存块被修改),一般返回const引用。

将引用用于对象

string类定义了一种char* 到string的转换功能,这使得可以使用C-风格字符串来初始化string对象。

基类引用可以指向派生类对象,而无需进行强制类型转换。

传递类对象的标准方式是按引用传递。

C++的输出格式化:

 1 #include<iostream>
 2 using namespace std;
 3 int main()
 4 {
 5     ios_base::fmtflags inits;//数据类型ios_base::fmtflags声明的变量用于存储,给此变量赋值前的所有格式化设置
 6     double x = 3333.0;
 7 //    cout.setf(ios_base::fixed);//定点表示法
 8 //    cout.setf(ios_base::showpoint);//将对象置于显示小数点的模式
 9     cout.precision(2);//设置显示精度
10     inits = cout.width(15);//设置字段宽度
11     cout << x << endl;
12     cout.setf(inits);//返回inits之前的所有格式化设置
13     cout << x << endl;
14     char str[4] = "abc";
15     cout << str[3] << endl;
16     system("pause");
17     return 0;
18 }

默认参数

函数重载:

默认参数让程序员能够使用不同数目的参数调用同一个函数,而函数多态(重载)使能够使用多个重名的函数。

函数重载的关键是函数的参数列表——也称函数特征标(function signature)。

C++允许定义名称相同的函数,条件是它们的特征标不同(返回类型可以相同也可以不同)。

如果参数类型和/或参数数目不同,则特征标也不同。

C++在检查特征标时,将类型和类型引用视为同一特征标,而不会将const和非const变量视为同一特征标。

若一个函数有多个重载版本的话,将调用最匹配的版本。

名称修饰:

C++编译器通过名称修饰(将函数名转换成内部表示,来描述接口,修饰时使用的约定随编译器而定),来跟踪每一个重载函数。

函数模板

函数模板使用泛型来定义函数。

定义普通模板的示例:

template <typename T> //or "class T"
void Swap(T &a, T &b)
{
  pass;
}

函数模板不能用来缩短可执行函数,最终代码不包含任何模板,而只包含程序生成时的实际函数。

使用模板的好处是,它使生成多个函数定义更简单、更可靠。

模板通常放在头文件中。

并非所有的模板都必须是模板参数类型,模板函数也可以重载。

模板的局限性:

有些类型并不支持一些函数内定义的运算,这时就对一些类型造成了限制。

有两种解决方案:1. 重载运算符; 2. 为具体类型提供具体化的模板定义。

模板的具体化:

1. 对于给定的函数名可以有非模板函数、模板函数和显示具体化模板函数以及它们的重载版本;

2. 显示具体化的原型和定义以template <>开头;

3. 具体化优先于常规模板,而非模板函数优先于具体化和常规模板。

隐式实例化(implicit instantiation)、显式实例化(explicit instantiation)和显式具体化(explicit specialization)统称为具体化(specialization)。

在声明中使用前缀template和template <>以区分显式实例化和显式具体化。

重载解析:

C++有一个良好的策略,来决定使用哪一个函数定义。

使函数调用参数与可行的候选函数的参数匹配所要进行的转换,从最佳到最差的顺序如下所述:

1. 完全匹配,但常规函数优于模板函数;

2. 提升转换(例如,char和short自动转换为int,float自动转换为double);

3. 标准转换(例如,int转换为char,long转换为double)。

若是指针和引用指向的数据有const和非const之间的区别,不会产生二义性(ambiguous);若是普通常量,则没有const和非const的区别。

如果两个完全匹配的函数都是模板函数,则较具体的模板函数优先(执行的转换最少的优先)。

找出最具体的模板的规则被称为函数模板的部分排序规则。

创建自定义选择

如lesser(...)有模板函数和非模板函数两个版本,在调用中使用:

lesser<>(...);
lesser<int>(...)

将自定义选择模板函数。

C++11中模板函数的改善

1. C++11新增了关键字decltype,解决模板函数中类型定义的问题。

template<class T1, class T2>
void ft(T1 x, T2 y)
{
  ...
  decltype(x+y) xpy = x+y;
  ...
}

2. C++11后置返回类型。

auto h(int x, float y) -> double
{/*function body*/}

其中auto是一个占位符,表示后置返回类型提供的类型。

时间: 2024-08-06 16:12:20

第八章 函数幽探的相关文章

第八章 函数

#1. #A:函数的定义与使用 #B:传递实参的方法有:位置实参.关键字实参.注意:这两种方式不能混用 #C:python不支持函数重载 #D:函数默认形参必须是不可变对象,可以指定为None def fun(value0, value1 = None, value2 = "szn"): print(str(value0) + " " + str(value1) + " " + str(value2)) fun(1, 2, "s&quo

Python编程从入门到实践第八章-函数

8-1 def display(): print("I will learn function in this chapter")#函数 function chapter章节 display() 8-2 def favorite_book(title): print("One of my favorite book is " + title.title() + ".") favorite_book('sword coming') 8-3 def

JavaScript基础学习之-JavaScript权威指南--8.1-8.4函数

第八章函数 函数是JavaScript中很重要的一个章节,懂得这个章节就可以轻松阅读别人的代码,会熟悉一些不常用的代码写法. 按照难易程度控制文章的长度. 前言: 函数是一段只定义一次,可能被执行或调用任意次的JavaScript代码. 若一个函数挂载在一个对象上,作为对象的属性,称为对象的方法.当通过这个对象来调用函数时,该对象就是此次调用的上下文,函数会隐式自动获得上下文对象. JavaScript中函数即对象,程序可以任意操控. JavaScript的函数可以嵌套在其他函数中定义,这样嵌套

Python虚拟机之函数机制(一)

PyFunctionObject对象 在Python中,任何一个东西都是对象,函数也不例外.函数这种抽象机制,是通过一个Python对象--PyFunctionObject来实现的 typedef struct { PyObject_HEAD PyObject *func_code; //编译后的PyCodeObject对象 PyObject *func_globals; //函数运行时的global名字空间 PyObject *func_defaults; //默认参数(tupple或NULL

python入到到实战--第八章

第八章 函数 定义函数 关键字def def get_name(): print("测试函数代码") 调用函数 get_name() 向函数传递信息------在函数的括号内添加需要传递的信息 实参和形参 在函数定义时,函数括号内的参数是形参: 在调用函数时,函数括号内的参数是实参: 传递参数----还可以使用列表和字典 位置实参:实参的顺序和形参的顺序相同---------顺序很重要,如果顺序错误,则实际结果会跟预期结果差别 关键字实参:每个实参由变量名和值组成: 位置实参: def

Linux Socket编程注意事项

Socket API 是网络应用程序开发中实际应用的标准 API.虽然该 API 简单.可是开发新手可能会经历一些常见的问题.本文识别一些最常见的隐患并向您显示怎样避免它们. 隐患 1.忽略返回状态 第一个隐患非常明显,但它是开发新手最easy犯的一个错误. 假设您忽略函数的返回状态,当它们失败或部分成功的时候,您或许会迷失. 反过来.这可能传播错误.使定位问题的源头变得困难. 捕获并检查每个返回状态.而不是忽略它们.考虑清单 1 显示的样例,一个套接字 send 函数. 清单 1. 忽略 AP

Linux 网卡驱动学习(二)(网络驱动接口小结)

[摘要]前文我们分析了一个虚拟硬件的网络驱动样例.从中我们看到了网络设备的一些接口.事实上网络设备驱动和块设备驱动的功能比較相似,都是发送和接收数据包(数据请求). 当然它们实际是有非常多不同的. 1.引言 首先块设备在/dev文件夹下有设备节点.而网络设备没有这种设备入口. read,write等常规的文件接口在网络设备下也没有意义. 最大的差别在于:块设备仅仅响应内核的数据请求:而网络设备驱动要异步地接收来自外部的数据包.简单地说.块设备驱动是被要求数据传输而网络设备是主动请求数据传输.网络

《C与指针》读后感

到目前为止,我已经读到了<C与指针>第十六章,总共十八章,接下来的章节内容分别是标准函数库.数据结构.以及C语言的运行环境,还没有完全做完练习就写这篇读后感原因有二,第一个当然是最主要的,这本书的前面十五章已经差不多完全概括这门语言的精髓了,第二个原因就是我很懒,懒得做下面的习题,这些习题的答案在网上都找得到,不过中文的解释倒是不多,所以我才一边做练习一边试着翻译答案,不过英语水平确实不太高,翻译的也不太好,大概意思吧. 接下来说正题,这本书--<C与指针>,这本书并不是很适合初学

c语言入门经典(第5版)

文章转载:http://mrcaoyc.blog.163.com/blog/static/23939201520159135915734 文件大小:126MB 文件格式:PDF    [点击下载] C语言入门经典(第5版)  内容简介: C语言是每一位程序员都应该掌握的基础语言.C语言是微软.NET编程中使用的C#语言的基础:C语言是iPhone.iPad和其他苹果设备编程中使用的Objective-C语言的基础:C语言是在很多环境中(包括GNU项目)被广泛使用的C++语言的基础.C语言也是Li