《C++ Primer Plus》《8、函数探幽》

1C++内联函数

内联函数是C++为了提高运行程序而做出的改进。他与常规函数的区别在于C++编译器如何将他组合到程序中。下面我们对常规函数的调用做一些概念上的说明:执行到函数调用指令时,程序将在函数调用后立即存储该指令的内存地址,并将函数参数复制到堆栈,跳到标记函数起点的内存单元,执行函数代码,然后跳回到地址被保存的指令处。书中有一个详细的比喻,你看书的时候,有的地方看不懂,需要到书脚看一下注释,然后再到书中接着看,内联函数怎么操作,他直接把注脚写到书中去。
使用内联函数需要考虑实际情况。时间短的代价是花费了更多的内存空间,需要在编写代码时有所取舍。
使用内联函数,需要做一些特殊的说明:
1)在函数声明前加上关键字inline;
2)在函数定义前加上关键字inline;
内联函数与C语言的宏定义很像,但还是有所区别的,内联函数和其他函数一样都是按值传递的,宏只是单纯的文本替换。

2引用变量

C++新增了一种复合类型——引用变量,引用是对一个变量的别名。例如一个人叫张三,外号“法外狂徒”,你在别人面前提起“法外狂徒”的时候,别人都知道你说的是张三。引用变量的主要用途是用作函数的形参,通过将引用变量用作参数,函数将使用原始数据,而不是其副本。

2.1创建引用变量

&在C语言中表示获取变量的地址,在C++中增加了引用的含义。

int a;
int & A = a; 此时A与a指向相同的数值和内存单元。

注意:在声明引用时,就立刻把他初始化。
书中给出了2个示例。
引用不同于指针,引用必须在声明时进行初始化,而不像指针可以先声明再赋值。引用一旦与某个变量关联起来就一直“忠于”他;而指针可以改变自己的指向。

2.2将引用用作函数参数

按引用传递允许被调用的函数能够访问调用函数中的变量。C语言只能按值传递,按值传递导致被调用的函数调用程序中数值的拷贝,要是避开按值传递的限制,只能按照指针传递。C++的引用传递突破了这个限制。
在这里插入图片描述

2.3引用的属性和特别之处

书中以计算数字的平方为例,向cube()函数(按值传递),recube()函数(按引用传递),按值传递没有改变原来变量的数值,但是按引用传递改变了原来变量的数值。
recube函数只能接受左值,如果传递给他一个右值,就会报错;在函数的定义中,在按引用传递之前加一个const,便解决了这个问题。因为const做了额外的操作,他在处理过程中生成了一个临时变量,避免了错误的发生。得出的结论:
应尽可能使用const
(1)使用const可以避免无意中修改数据的编程错误;
(2)使用const使得函数能够处理const和非const实参,否则只能接受非const数据;
(3)使用const引用使函数能够正确生成并使用临时变量;

2.4将引用用于结构

书中给出了示例程序

2.5将引用用于类

书中给出了示例程序

2.6对象、继承和引用

书中给出了示例代码,让计算结果,在平台上输出,在文件中输出。

2.7何时使用引用参数

使用引用参数的主要原因:
(1)可能回修改调用函数中的数据对象;
(2)通过传递引用,会提高程序的运行速度(主要原因)。
对函数参数选择的指导意见:
对于使用传递的值而不作修改的函数:
(1)如果数据对象很小,则按值传递;
(2)如果数据对象是数组,使用指针;
(3)如果数据对象是较大的结构,使用const指针或者const引用;
(4)如果数据对象是类对象,则使用const引用;
对于修改调用函数中数据的函数:
(1)如果数据对象是内置数据类型,则使用指针;
(2)如果数据对象是数组,使用指针;
(3)如果数据对象是结构,使用引用或指针;
(4)如果数据对象是类对象,则使用引用;

3默认参数

默认参数指的是当函数调用中省略了实参时自动使用的一个值。
对于带参数列表的函数,必须从右向左添加默认值;
书中给出了示例代码。

4函数重载

函数“多态”能够使用多个同名的函数。 可以通过函数重载来设计一系列函数——他们完成相同的工作,但使用不同的参数列表。

4.1重载示例

书中给出了示例代码。

4.2何时使用重载函数

仅当函数基本上执行相同的任务,但使用不同形式的数据时才应该采用重载函数。

5函数模板

函数模板是函数重载的升级,之前函数重载时候,遇到不同类型的参数,需要额外进行说明,但模板类可以在此基础上进行升级。函数模板用泛型来定义函数,其中的泛型可以用具体的类型进行替换,通过将类型作为参数传递给模板,可以使编译器生成该类型的函数。
书中给出了示例模板。

5.1重载的模板

之前给出了一个交换数值的模板,交换int型数值和double类型数值。但是如果传给他一个数组,他是不能处理的。为了能够交换数组,新增了一个交换模板。

5.2模板的局限性

编写的模板函数,不可能处理所有类型,必定存在一些类型是无法处理的。

5.3显式具体化

以交换结构体的成员变量为例写一个交换函数,这时候之前的模板函数已经不能再使用了;这时候需要提供一个具体化函数定义——显示具体化。
对于显示具体化的说明:
(1)对于给定的函数名,可以有非模板函数,模板函数,显示具体化模板函数以及他们的重载版本;
(2)显示具体化的原型和定义应该以templete<>打头,并通过名称指出类型;
(3)具体化优先于常规模板,非模板函数优先于具体化和常规模板;
书中给出了显示具体化的示例。

5.4实例化和具体化

这是两个术语,在代码中包含函数模板本身并不会生成函数定义,他只是一个用于生成函数定义的方案;编译器使用模板为特定类型生成函数定义时,得到的是模板实例。
模板实例化分为2种,隐式实例化和显式实例化
在C++中,函数模板实例化是指根据模板定义生成特定类型的函数代码。当使用函数模板时,编译器会根据传递给函数的实参推导出相应的模板参数,并生成对应的函数实例。
函数模板的实例化有两种方式:
隐式实例化:当调用函数模板时,编译器会自动根据传递的实参进行模板参数推导,并生成相应的函数实例。例如:

template <typename T>
void Print(T value) {
    std::cout << value << std::endl;
}

int main() {
    Print(10); // 隐式实例化为 void Print<int>(int value)
    Print("Hello"); // 隐式实例化为 void Print<const char*>(const char* value)
    return 0;
}

在这个例子中,当调用 Print(10) 时,编译器会隐式实例化函数模板 Print 为 void Print(int value);当调用 Print(“Hello”) 时,编译器会隐式实例化函数模板 Print 为 void Print<const char*>(const char* value)。
显式实例化:开发人员也可以显式地告诉编译器要实例化哪些函数模板,这样可以在编译时生成特定类型的函数实例。例如:

template <typename T>
void Print(T value) {
    std::cout << value << std::endl;
}
// 显式实例化为 void Print<int>(int value)
template void Print<int>(int value);
int main() {
    Print("Hello"); // 隐式实例化为 void Print<const char*>(const char* value)
    return 0;
}

在这个例子中,通过 template void Print(int value) 的显式实例化语句,开发人员告诉编译器要生成特定类型 int 的函数实例。
函数模板的实例化使得可以在编译时根据具体的类型生成对应的函数代码,提供了更高的灵活性和重用性。
模板具体化:
在C++中,模板具体化(Template Specialization)是一种特殊的技术,用于为特定类型或特定模板参数提供自定义实现。具体化允许开发人员根据特定的需求,为模板生成专门优化的代码。
具体化的作用包括以下几个方面:
(1)提供针对特定类型的优化:通过具体化,可以为特定类型提供更高效的代码实现。例如,当某个算法在大多数情况下都能正常工作,但对于某些特定类型的数据需要不同的处理方式时,可以使用具体化来提供这种特殊情况下的优化代码。
(2)解决特定类型的特殊需求:有时候某些类型可能对于通用模板的实现方式不适用,或者要求特定的行为。通过具体化,可以为这些特殊类型提供自定义的实现。这样就能够在一个通用的模板中处理大多数情况,并为特殊类型提供定制的代码。
(3)避免代码冗余:具体化还可以避免代码的重复,提高代码的可维护性和可读性。通过为特定类型提供专门的实现,可以避免在多个地方复制相似的代码。
需要注意的是,具体化应该谨慎使用,因为它可能引入代码重复和维护困难的问题。在大多数情况下,通用模板应该能够满足需求。只有在特定类型需要特殊处理时,才应该考虑使用具体化。

5.5编译器选择使用哪个函数版本

对于函数重载,函数模板和函数模板重载,C++需要一个定义良好的策略,来决定为函数调用使用哪一个函数定义,这个过程称为重载解析。重载解析的过程如下:
(1)创建候选函数列表;
(2)使用候选函数列表创建可行函数列表;
(3)确定是否有最佳的可行函数。
书中给出了示例代码。

5.6 模板函数的发展

C++11标准引入了类型和关键字decltype。

6 总结

C++扩展了C语言函数上的功能,新增了内联函数;函数的特征标是参数列表;只要特征标不同,函数可以同名。函数模板会自动完成重载函数的过程,只需要使用泛型和具体算法来定义函数,编译器将为程序中使用的特定参数类型生成正确的函数定义。

7 参考

7.1 《C++ Primer Plus》

  • 50
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值