C++PrimerPlus学习笔记之函数探幽-创新互联
个人觉得学习编程最有效的方法是阅读专业的书籍,通过阅读专业书籍可以构建更加系统化的知识体系。
一直以来都很想深入学习一下C++,将其作为自己的主力开发语言。现在为了完成自己这一直以来的心愿,准备认真学习《C++ Primer Plus》。
为了提高学习效率,在学习的过程中将通过发布学习笔记的方式,持续记录自己学习C++的过程。
内联函数是C++为提高程序运行速度所做的一项改进。常规函数和内联函数之间的主要区别不在于编写方式,而在于C++编译器如何将它们组合到程序中。
对于内联代码,程序无需跳到另一个位置处执行代码,再跳回来。因此,内联函数的运行速度比常规函数稍快,但代价是需要占用更多内存。如果程序在10个不同的地方调用同一个内联函数,则该程序将包含该函数代码的10个副本。
要使用这项特性,必须采取下述措施之一:
- 在函数声明前加上关键字
inline
; - 在函数定义前加上关键字
inline
。
通常的做法是省略原型,将整个定义(即函数头和所有函数代码)放在本应提供原型的地方
C++新增了一种复合类型——引用变量。引用是已定义的变量的别名(另一个名称)。
C和C++使用&
符号来指示变量的地址。C++给&
符号赋予了另一个含义,将其用来声明引用。例如,要将rodents
作为rats
变量的别名,可以这样做:
int rats;
int & rodents = rats;
int &
指的是指向int
的引用。
引用经常被用作函数参数,使得函数中的变量名成为调用程序中的变量的别名。这种传递参数的方法称为按引用传递。按引用传递允许被调用的函数能够访问调用函数中的变量。
如果意图是让函数使用传递给它的信息,而不对这些信息进行修改,同时又想使用引用,则应使用常量引用:
double refcube(const double &ra);
如果实参与引用参数不匹配,C++将生成临时变量。当前,仅当参数为const
引用时,C++才允许这样做,但以前不是这样。
如果引用参数是const
,则编译器将在下面两种情况下生成临时变量:
- 实参的类型正确,但不是左值;
- 实参的类型不正确,但可以转换为正确的类型。
**左值参数:**是可被引用的数据对象,例如,变量、数组元素、结构成员、引用和解除引用的指针都是左值。
**非左值:**包括字面常量(用引号括起的字符串除外,它们由其地址表示)和包含多项的表达式。在C语言中,左值最初指的是可出现在赋值语句左边的实体,但这是引入关键字const
之前的况。现在,常规变量和const
变量都可视为左值,因为可通过地址访问它们。但常规变量属于可修改的左值,而const
变量属于不可修改的左值。
将引用参教声明为常量数据的引用的理由有三个:
- 使用
const
可以避免无意中修改数据的编程错误; - 使用
const
使函数能够处理const
和非const
实参,否则将只能接受非const
数据; - 使用
const
引用使函数能够正确生成并使用临时变量。
C++11新增了另一种引用——右值引用(rvalue reference)。这种引用可指向右值,是使用&&
声明的:
double && rref = std::sqrt(36.00);
新增右值引用的主要目的是,让库设计人员能够提供有些操作的更有效实现。
引用非常适合用于结构和类(C++的用户定义类型)。
返回引用的函数实际上是被引用的变量的别名。
返回引用时最重要的一点是,应避免返回函数终止时不再存在的内存单元引用。为避免这种问题,最简单的方法是,返回一个作为参数传递给函数的引用。另一种方法是用new
来分配新的存储空间。
使得能够将特性从一个类传递给另一个类的语言特性被称为继承。
继承的另一个特征是,基类引用可以指向派生类对象,而无需进行强制类型转换。
使用引用参数的主要原因有两个:
- 程序员能够修改调用函数中的数据对象。
- 通过传递引用而不是整个数据对象,可以提高程序的运行速度。
对于使用传递的值而不作修改的函数。
- 如果数据对象很小,如内置数据类型或小型结构,则按值传递。
- 如果数据对象是数组,则使用指针,因为这是唯一的选择,并将指针声明指向
const
的指针。 - 如果数据对象是较大的结构,则使用
const
指针或const
引用,以提高程序的效率。这样可以节省复制结构所需的时间和空间。 - 如果数据对象是类对象,则使用
const
引用。类设计的语义常常要求使用引用,这是C++新增这项特性的主要原因。因此,传递类对象参数的标准方式是按引用传递。
对于修改调用函数中数据的函数:
- 如果数据对象是内置数据类型,则使用指针。如果看到诸如txi(&x)这样的代码(其中×尼imnt)则很明显,该函数将修改x。
- 如果数据对象是数组,则只能使用指针。
- 如果数据对象是结构,则使用引用或指针。
- 如果数据对象是类对象,则使用引用。
当然,这只是一些指导原则,很可能有充分的理由做出其他的选择。
默认参数指的是当函数调用中省略了实参时自动使用的一个值。
char * left(const char * str, int n = 1);
对于带参数列表的函数,必须从右向左添加默认值。也就是说,要为某个参数设置默认值,则必须为它右边的所有参数提供默认值。
四、函数重载函数多态是C++在C语言的基础上新增的功能。术语“多态”指的是有多种形式,因此函数多态允许函数可以有多种形式。类似地,术语“函数重载"’指的是可以有多个同名的函数,因此对名称进行了重载。这两个术语指的是同一回事,但我们通常使用函数重载。
函数重载的关键是函数的参数列表——也称为函数特征标(function signature)。编译器在检查函数特征标时,将把类型引用和类型本身视为同一个特征标。
五、函数模板函数模板是通用的函数描述,也就是说,它们使用泛型来定义函数,其中的泛型可用具体地类型(如int 或 double)替换。由于类型是用参数表示的,因此模板特性有时也被称为参数化类型。
templatevoid Swap(AnyType &a, AnyType &b)
{AnyType temp;
temp = a;
a = b;
b = temp;
}
关键字template
和typename
是必需的,除非可用使用关键字class
代替typename
。另外,必须使用尖括号。
在标准C++98添加关键字typename
之前,C++使用关键字class
来创建模板。也就是说,可以这样编写模板定义:
templatevoid Swap(AnyType &a, AnyType &b)
{
AnyType temp;
temp = a;
a = b;
b = temp;
}
可以提供一个具体化函数定义——称为显式具体化(explicit specialization),其中包含所需的代码。
C++98标准选择了下面的具体化方法:
- 对于给定的函数名,可以有非模板函数、模板函数和显式具体化模板函数以及它们的重载版本。
- 显示具体化的原型和定义应以
template<>
打头,并通过名称来指出类型。 - 具体化优先于常规模板,而非模板函数优先于具体化和常规模板。
template<>void Swap(job & , job &);
为进一步了解模板,必须理解术语实例化和具体化。记住,在代码中包合函数模板本身并不会生成函数定义,它只是一个用于生成函数定义的方案。编译器使用模板为特定类型生成明数定义时,得到的是模板实例(instantiation)。这种实例化方式被称为隐式实例化(implicit instantiation)。
现在C++还允许显式实例化(explicit instantiation):
template void Swap(int, int);
与显式实例化不同的是,显式具体化使用下面两个等价的声明之一:
template<>void Swap(int &, int &);
template<>void Swap(int &, int &);
区别在于,这些声明的意思是“不要使用Swap()
模板来生成函数定义,而应使用专门为int
类型显式地定义的函数定义”。这些原型必须有自己的函数定义。
显式具体化声明在关键字template
后包含<>
,而显式实例化没有。
完全匹配允许的无关紧要的转换:
从实参 | 到形参 |
---|---|
Type | Type & |
Type & | Type |
Type [] | * Type |
Type(argument-list) | Type (*)(argument-list) |
Type | const Type |
Type | volatile Type |
Type * | const Type |
Type * | volatile Type * |
指向非const
数据的指针和引用]优先与非const
指针和引用参数匹配。
其中一个是非模板函数,而另一个不是。在这种情况下,非模板函数将优先于模板函致(包括显式具体化)。
如果两个完全匹配的函数都是模板函数,则较具体的模板函数优先。
templatevoid ft(T1 x, T2 y)
{?type? xpy = x + y;
}
以上代码中xpy
的类型无法明确,可以通过C++11新增关键字decltype
来解决:
templatevoid ft(T1 x, T2 y)
{decltype(x + y) xpy = x + y;
}
template?type? ft(T1 x, T2 y)
{return x + y;
}
以上代码中返回类型无法明确,可以通过auto
关键字和关键字decltype
组合使用来解决:
templateauto ft(T1 x, T2 y) ->decltype(x + y)
{return x + y;
}
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧
网站栏目:C++PrimerPlus学习笔记之函数探幽-创新互联
分享网址:http://scyanting.com/article/piocd.html