C++函数模板

c++ obj文件

obj文件就是目标文件,是源程序经过编译程序编译后生成的
不能直接执行,需要连接程序连接后才能生成可执行文件,这样就能执行
一般由机器代码组成,但也可以是自己定义的一些伪指令代码(需有专门的解释程序对其进行解释执行)

连接程序

把目标代码和它所使用的库文件连接的程序
obj文件与exe文件的区别

编译

  当前源代码编译成二进制目标文件(obj文件)

链接(link)

  将生成的.obj文件与库文件.lib等文件链接,生成可执行文件(.exe文件)
project中每个cpp经编译成为obj(object)文件,所有obj文件和资源问价经连接(link)成为可执行文件,obj文件可称为目标文件或中间文件。obj文件只给出了程序的相对地址,而exe是绝对地址

现代编译器的主要工作流程

源程序(source code)→ 预处理器(preprocessor)→ 编译器(compiler)→ 汇编程序(assembler)→ 目标程序(object code)→ 连接器(链接器,Linker)→ 可执行程序(executables)

函数模板的声明和实现

函数模板的声明和实现一般都放在.h文件中。
  模板是在需要的时候,才会去生成一个具体的实例化。模板本身是不会被执行的(模板本身不产生汇编指令),是模板生成的具体实例化才产生指令。

模板的实现为什么放在.h中

  编译器一次只能处理一个单元,即一次处理一个cpp文件,实例化时需要看到该模块的完整定义,若头文件中只有声明,没有定义,编译器就无法实例化该模块,最终会导致链接(link)错误,所以放在头文件中。
  关于这一点我再解释一下:其他的函数声明放在h文件,函数定义放在cpp文件的原因是在编译阶段只要保证每个单独生成obj的cpp文件在编译阶段是自身完整的,cpp中使用的函数,是可以在#include的头文件中直接查找到声明的,而模板函数如果只在h文件中声明模板,cpp中直接要使用实例化后的函数,需要的是实例化后的函数声明,就找不到了。所以就把函数模板的实例化放在编译阶段,编译阶段的cpp是单独运行的,不和其他的cpp产生关系,所以函数模板不能放在其他的cpp。

  若你坚持不想放在.h中,试试include "xxx.cpp"这种奇葩的做法也是可以的。补充:为什么include "xxx.cpp"可以呢?因为include "xxx.cpp"相当于代码的复制粘贴,相当于把include "xxx.cpp"里的函数模板定义直接添加到当前cpp中,那当前cpp在编译阶段就是自身完整的了。


函数模板的来源与实例

  重载函数使编程变得方便,因为对于执行类似操作的一组函数,只要记住一个函数名称即可。但是,每个函数都必须单独编写。例如,来看以下重载的 square 求平方函数:

int square(int number)
{
    return number * number;
}
double square(double number)
{
    return number * number;
}

  这两个函数之间的唯一区别是它们的返回值及其形参的数据类型。在这种情况下,编写函数模板比重载函数更方便。函数模板允许程序员编写一个单独的函数定义,以处理许多不同的数据类型,而不必为每个使用的数据类型编写单独的函数。
  函数模板不是实际的函数,而是编译器用于生成一个或多个函数的 “模具”。在编写函数模板时,不必为形参、返回值或局部变量指定实际类型,而是使用类型形参来指定通用数据类型。当编译器遇到对函数的调用时,它将检查其实参的数据类型,并生成将与这些数据类型配合使用的函数代码。
以下是一个 square 函数的函数模板:

template<class T>
T square(T number)
{
    return number * number;
}

  在上面的 square 函数模板示例中,只使用了一个名为 T 的形参(如果有更多的话,它们将用逗号分隔)。在此之后,除了使用类型形参代替实际的数据类型名称之外,其他的都可以像往常一样写入函数的定义。在本函数模板示例中,以下是其函数头:

T square(T number)

  其中,T 是类型形参或通用数据类型。该函数头定义了一个 square 函数,它返回一个 T 类型的值,并使用了一个形参 number,这也是 T 类型的数字。
  如前所述,编译器会检查对 square 的每次调用,并以适当的数据类型填充 T,例如,以下调用将使用 int 参数:

int y, x = 4;
y = square(x);

以上代码将导致编译器生成以下函数:

int square(int number)
{
    return number * number;
}

但是,如果使用以下语句调用 square 函数:

double y, d = 6.2;
y = square(d);

那么编译器生成的函数将如下所示:

double square(double number)
{
    return number * number;
}

下面的程序演示了该函数模式的用法:

// This program uses a function template.
#include <iostream>
#include <iomanip>
using namespace std;
// Template definition for square function
template <class T>
T square(T number)
{
    return number * number;
}
int main()
{
    cout << setprecision(5);
    //Get an integer and compute its square
    cout << "Enter an integer: ";
    int iValue;
    cin >> iValue;
    // The compiler creates int square(int) at the first occurrence of a call to square with an int argument
    cout << "The square is " << square(iValue);
    // Get a double and compute its square
    cout << "\nEnter a double: ";
    double dValue;
    cin >> dValue;
   
    // The compiler creates double square(double)at the first
    // occurrence of a call to square with a double argument
    cout << "The square is " << square (dValue) << endl;
    return 0;
}

程序输出结果:
在这里插入图片描述
注意:函数模板仅仅是函数的规范,本身并不会导致使用内存。当编译器遇到对模板函数的调用时,才会在内存中创建该函数的实际实例。


后记

  关于template声明模板时用Typename还是Class,目前看到2种说法:

  1. 第一种说法: template 用于基础数据类型,typename 指类型名,T 可以取 char int double 等。template 用于类,T 可以取任何类。结构体可以用 typename 或 class
  2. 第二种说法:最早的时候只有class,后来统一用typename,但是还是可以兼容class。
      由于目前还没用到,不知真伪,后续遇到这个问题再来补充。

来源/参考 致谢

本文来自于:
https://blog.csdn.net/qq_29339467/article/details/91633427
http://c.biancheng.net/view/1565.html
感谢2位原作者。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值