C++中函数模版与类模版

本文涉及的产品
实时计算 Flink 版,5000CU*H 3个月
智能开放搜索 OpenSearch行业算法版,1GB 20LCU 1个月
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
简介: C++中函数模版与类模版

1、什么是模板?

(1)可以这样来解释这个问题,例如当我们需要定义多个函数,而这个函数功能其实都是一样的,例如两个数相加的函数,

只是相加的两个数的类型不相同而已,这就导致我们需要定义多个函数;当我们使用了函数模板之后,我们只需要定义

一个函数模板,这个函数模板的功能就是实现两个数相加的操作,而且可以传入自己指定的数据类型,这样我们就不用定义

多个函数了,所以可以认为,模板就是一种可以产生一系列功能相同而数据类型不同的函数或者是类的 "机器"

(2)模板的形式:函数模板、类模板

(3)模板的声明格式

函数模板

    template<typename 类型参数>              

    返回类型 函数名(模板形参表)

   {

   函数体

  }

   

 template<class 类型参数>

    返回类型 函数名(模板形参表)

    {

        函数体

    }

类模板

      template <typename 类型参数>

  class 类名

  {

    类成员声明

  }

  或

  template <class 类型参数>

  class 类名

  {

    类成员声明

  }

在上面的template后面的参数可以是多个,也可以是一个,而且修饰词typename和class可以混用,可以认为他们两个关键字没有什么区别,都可以使用;

template后面的"<>"尖括号可以紧跟在template关键字后面,也可以用空格来隔开;

(4)需要注意的是:typename或者是class指定的是一种数据类型,其实除了可以指定数据类型之外,还可以指定某种数据类型的变量,例如下面的

         template <typename 形参名,class 形参名,int 形参名,  double 形参名, ......>

typename和class后面的表示的是某种数据类型的形参名,将来在使用模板函数的时候传入自己指定的数据类型;而int和double后面的表示的是

这种数据类型的变量,将来在使用模板函数的时候自己传入自己的变量。所以对于模板的形参总共就是分为这两类:类型形参和非类型形参。

2、模板函数和模板类的使用

函数模板定义及其使用:

#include <iostream>
using namespace std;

template <typename T>     // 声明函数模板
static T Add1(T a, T b)
{
    return (a + b);
}

template <class T, int count>  // 声明函数模板
static void Print(T a)
{
    int i = 0;

    for (i = 0; i < count; i++)
        cout << a << " ";
    cout << endl;
}

int main(void)
{
    cout << Add1<int>(10, 20) << endl;  // 使用模板函数
    Print<int, 5>(10);                  // 使用模板函数
    return 0;
}

类模板定义及其使用:

#include <iostream>
using namespace std;

template <typename T, int Ksize, int Kval>
class Array{
public:
    Array(void);         // 构造函数
    ~Array(void) { delete[]p_Arr; p_Arr = NULL; }        // 析构函数 类内定义方式
    void display(void);
private:
    T *p_Arr;
};

template <typename T, int Ksize, int Kval>      // 类外定义方式
Array<T, Ksize, Kval>::Array(void)
{
    p_Arr = new T[Ksize];
    int i = 0;

    for (i = 0; i < Ksize; i++)
        p_Arr[i] = Kval;
}

template <typename T, int Ksize, int Kval>   // 类外定义方式
void Array<T, Ksize, Kval>::display(void)
{
    int i = 0;

    for (i = 0; i < Ksize; i++)
        cout << p_Arr[i] << " ";
    cout << endl;
}

int main(void)
{
    Array<int, 10, 10> arr;
    arr.display();
    return 0;
}

运行结果分别如下所示:

868435d2665a34c7c77b63ffa409aae3_944893-20161101111505205-881431608.png 23a8cea2e67608cdd3d5ef68b31416dc_944893-20161101113453705-1937803357.png

(1)对于模板函数的使用需要注意的是:我们需要在函数名之后添加一对尖括号,将需要传给函数模板的参数写进去: Add1<int>(10, 20);

但是其实不加 <int> 也是可以的,但是前提条件是函数的参数类型都是相同的,否则就会编译出错:

Add1(10, 20)         // 这样是可以的,因为10 和 20 数据类型相同

Add1(10, 20.0)      // 这就不行,数据类型不相同

(2)对于类模板需要注意的是:除了在类模板声明前加上 template <......> 之外,如果成员函数是在类内定义倒没什么可说的,如果是在类外定义的,那么就需要注意了

每个在类外定义的所有成员函数之前都要加上 template <......>,而且函数名前面还要加上 <.....>,里面的内容是参数名,如下所示:

 template <typename T, int Ksize, int Kval>      // 类外定义方式

 Array<T, Ksize, Kval>::Array(void)  {  }

(3)通过类模板来定义一个类对象的时候也是和函数差不多,也是需要加上 <...>,将要传给类模板的参数写进去即可: Array<int, 10, 10> arr;

2、模板本身不会占用内存空间,而定义的模板函数或者是模版类才会占用内存空间。

3、函数模板与同名非模板函数也可以重载。

#include <iostream>
using namespace std;

template <typename T>     // 声明函数模板
static T Add(T a, T b)
{
    cout << "模板函数" << endl;
    return (a + b);
}

static int Add(int a, int b)    // 普通函数
{
    cout << "普通函数" << endl;
    return (a + b);
}

int main(void)
{
    cout << Add(10, 20) << endl;
    return 0;
}

运行结果如下:从结构可以看出来,函数模板与同名非模板函数也可以重载,而且当我们调用函数的时候优先调用的是普通的函数,而不是模板函数。

3abaf04a987d588a1076a5c9cc1e40ed_944893-20161101134639518-1542512946.png

4、在template语句和函数模板定义语句之间是不允许插入其他的语句,并且一个 template<....> 只能对应一个模板的声明,而不用使用一个 template<....> 来声明多个函数模板或者是类模板。

相关文章
|
10天前
|
存储 编译器 C++
【c++】类和对象(中)(构造函数、析构函数、拷贝构造、赋值重载)
本文深入探讨了C++类的默认成员函数,包括构造函数、析构函数、拷贝构造函数和赋值重载。构造函数用于对象的初始化,析构函数用于对象销毁时的资源清理,拷贝构造函数用于对象的拷贝,赋值重载用于已存在对象的赋值。文章详细介绍了每个函数的特点、使用方法及注意事项,并提供了代码示例。这些默认成员函数确保了资源的正确管理和对象状态的维护。
37 4
|
11天前
|
存储 编译器 Linux
【c++】类和对象(上)(类的定义格式、访问限定符、类域、类的实例化、对象的内存大小、this指针)
本文介绍了C++中的类和对象,包括类的概念、定义格式、访问限定符、类域、对象的创建及内存大小、以及this指针。通过示例代码详细解释了类的定义、成员函数和成员变量的作用,以及如何使用访问限定符控制成员的访问权限。此外,还讨论了对象的内存分配规则和this指针的使用场景,帮助读者深入理解面向对象编程的核心概念。
35 4
|
30天前
|
程序员 C++ 容器
在 C++中,realloc 函数返回 NULL 时,需要手动释放原来的内存吗?
在 C++ 中,当 realloc 函数返回 NULL 时,表示内存重新分配失败,但原内存块仍然有效,因此需要手动释放原来的内存,以避免内存泄漏。
|
1月前
|
存储 编译器 对象存储
【C++打怪之路Lv5】-- 类和对象(下)
【C++打怪之路Lv5】-- 类和对象(下)
27 4
|
1月前
|
编译器 C语言 C++
【C++打怪之路Lv4】-- 类和对象(中)
【C++打怪之路Lv4】-- 类和对象(中)
23 4
|
1月前
|
存储 安全 C++
【C++打怪之路Lv8】-- string类
【C++打怪之路Lv8】-- string类
21 1
|
1月前
|
存储 前端开发 C++
C++ 多线程之带返回值的线程处理函数
这篇文章介绍了在C++中使用`async`函数、`packaged_task`和`promise`三种方法来创建带返回值的线程处理函数。
46 6
|
1月前
|
存储 编译器 C语言
【C++打怪之路Lv3】-- 类和对象(上)
【C++打怪之路Lv3】-- 类和对象(上)
17 0
|
1月前
|
Unix 编译器 Linux
C++之模版进阶篇(下)
C++之模版进阶篇(下)
47 0
|
1月前
|
编译器 C++
C++之模版进阶篇(上)
C++之模版进阶篇(上)
15 0