C++模板总结

  本文参考了博文:C++ TemplateC++模板详解为什么C++编译器不能支持对模板的分离式编译

  在编写含有模板的程序的时候,我还是按照一个头文件声明,一个源文件的方法来组织,结果编译的时候总出现一些很奇怪的语法问题,但程序明明是没有问题的。后来经过查阅才知道原来是因为C++编译器不支持对模板的分离式编译,详细原因可参考博文为什么C++编译器不能支持对模板的分离式编译。所以,我在编写程序的时候,使用的是模板声明和实现放在同一个文件中的方法,即使用后缀为.hpp的文件(当然也可以是.h文件,但用.hpp文件更方便表明声明和实现放在一起)。

  模板

  模板是C++支持参数化多态的工具,使用模板可以使用户为类或者函数声明一种一般模式,使得类中的某些数据成员或者成员函数的参数、返回值取得任意类型。

  模板是一种对类型进行参数化的工具;

  通常有两种形式:函数模板类模板

  函数模板针对仅参数类型不同的函数

  类模板针对仅数据成员成员函数类型不同的类。

  使用模板的目的就是能够让程序员编写与类型无关的代码。比如编写了一个交换两个整型int 类型的swap函数,这个函数就只能实现int 型,对double,字符这些类型无法实现,要实现这些类型的交换就要重新编写另一个swap函数。使用模板的目的就是要让这程序的实现与类型无关,比如一个swap模板函数,即可以实现int 型,又可以实现double型的交换。模板可以应用于函数和类。下面分别介绍。

  注意:模板的声明或定义只能在全局,命名空间或类范围内进行。即不能在局部范围,函数内进行,比如不能在main函数中声明或定义一个模板。

  1. 函数模板

   1)函数模板的格式

template <class 形参名,class 形参名,......> 返回类型 函数名(参数列表)
{
    函数体
}

  其中templateclass是关键字,class可以用typename 关见字代替,在这里typename 和class没区别,<>括号中的参数叫模板形参,模板形参和函数形参很相像,模板形参不能为空。一但声明了模板函数就可以用模板函数的形参名声明类中的成员变量和成员函数,即可以在该函数中使用内置类型的地方都可以使用模板形参名。模板形参需要调用该模板函数时提供的模板实参来初始化模板形参,一旦编译器确定了实际的模板实参类型就称他实例化了函数模板的一个实例。比如swap的模板函数形式为

template <class T> void swap(T& a, T& b)
{
}

  当调用这样的模板函数时类型T就会被被调用时的类型所代替,比如swap(a,b)其中abint 型,这时模板函数swap中的形参T就会被int 所代替,模板函数变为swap(int &a, int &b)。而当swap(c,d)其中cddouble类型时,模板函数会被替换为swap(double &a, double &b),这样就实现了函数的实现与类型无关的代码。

   2)注意

  对于函数模板而言不存在 h(int,int) 这样的调用,不能在函数调用的参数中指定模板形参的类型,对函数模板的调用应使用实参推演来进行,即只能进行 h(2,3) 这样的调用,或者int a, b; h(a,b)

   3)示例

1 // funcTemp.hpp
2 template<typename T> void swapTest(T& t1, T& t2)
3 {
4     T tmpT;
5     tmpT = t1;
6     t1 = t2;
7     t2 = tmpT;
8 }

funcTemp.hpp

 1 // main.cpp
 2 #include <iostream>
 3 #include "funcTemp.hpp"
 4
 5 using namespace std;
 6
 7 int main()
 8 {
 9     int num1 = 1, num2 = 2;
10     swapTest<int>(num1, num2);
11     cout << "num1: " << num1 << " num2: " << num2 << endl;
12     return 0;
13 }

main.cpp

   2. 类模板

  1) 类模板的格式

template<class  形参名,class 形参名,…>
class 类名
{
    ...
};

   类模板和函数模板都是以template开始后接模板形参列表组成,模板形参不能为空,一但声明了类模板就可以用类模板的形参名声明类中的成员变量和成员函数,即可以在类中使用内置类型的地方都可以使用模板形参名来声明。比如

 1 template<class T>
 2 class A
 3 {
 4 public:
 5     T a;
 6     T b;
 7     T hy(T c, T &d);
 8 };

  在类A中声明了两个类型为T的成员变量ab,还声明了一个返回类型为T带两个参数类型为T的函数hy

   2) 类模板对象的创建

  比如一个模板类A,则使用类模板创建对象的方法为A<int> m;在类A后面跟上一个<>尖括号并在里面填上相应的类型,这样的话类A中凡是用到模板形参的地方都会被int 所代替。当类模板有两个模板形参时创建对象的方法为A<int, double> m;类型之间用逗号隔开。

   3) 对于类模板,模板形参的类型必须在类名后的尖括号中明确指定。

  比如A<2> m;用这种方法把模板形参设置为int是错误的(编译错误:error C2079: ‘a‘ uses undefined class ‘A<int>‘),类模板形参不存在实参推演的问题。也就是说不能把整型值2推演为int 型传递给模板形参。要把类模板形参调置为int 型必须这样指定A<int> m

   4) 在类模板外部定义成员函数的方法

template<模板形参列表> 函数返回类型 类名<模板形参名>::函数名(参数列表){ 函数体 }

  比如有两个模板形参T1T2的类A中含有一个void h()函数,则定义该函数的语法为:

template<class T1, class T2> void A<T1, T2>::h(){}

  注意:当在类外面定义类的成员时template后面的模板形参应与要定义的类的模板形参一致。

  5) 再次提醒注意

  模板的声明或定义只能在全局,命名空间或类范围内进行。即不能在局部范围,函数内进行,比如不能在main函数中声明或定义一个模板。

   6) 示例1:栈(大小预定)

 1 // stackTest.hpp
 2 template<class T>
 3 class stackTest
 4 {
 5 public:
 6     stackTest();
 7     ~stackTest();
 8     void push(T t);
 9     T pop();
10     bool isEmpty();
11
12 private:
13     T *m_pT;
14     int m_maxsize;
15     int m_size;
16
17 };
18
19
20 template<class T> stackTest<T>::stackTest()
21 {
22     m_maxsize = 100;
23     m_size = 0;
24     m_pT = new T[m_maxsize];
25 }
26
27 template<class T> stackTest<T>::~stackTest()
28 {
29     delete[] m_pT;
30 }
31
32 template<class T> void stackTest<T>::push(T t)
33 {
34     m_size++;
35     m_pT[m_size - 1] = t;
36 }
37
38 template<class T> T stackTest<T>::pop()
39 {
40     T t = m_pT[m_size - 1];
41     m_size--;
42     return t;
43 }
44
45 template<class T> bool stackTest<T>::isEmpty()
46 {
47     return m_size == 0;
48 }

stackTest.hpp

 1 // main.cpp
 2 #include <iostream>
 3 #include"stackTest.hpp"
 4
 5 using namespace std;
 6
 7 int main()
 8 {
 9     stackTest<int> tmpStack;
10     tmpStack.push(1);
11     tmpStack.push(2);
12     tmpStack.push(3);
13
14     while (!tmpStack.isEmpty())
15     {
16         cout << tmpStack.pop() << endl;
17     }
18
19     return 0;
20 }

main

   7)示例2:栈(大小可配置)

  模板可以有类型参数,也可以有常规的类型参数int,也可以有默认模板参数,例如

template<class T, T def_val> class Stack{ ... }

  示例中的类模板的栈有一个限制,就是最多只能支持100个元素,我们可以使用模板参数配置这个栈的最大元素数,如果不配置,就设置默认最大值为100,代码如下:

 1 // stackTest.h
 2
 3 template<class T, int maxsize = 100>
 4 class stackTest
 5 {
 6 public:
 7     stackTest();
 8     ~stackTest();
 9     void push(T t);
10     T pop();
11     bool isEmpty();
12
13 private:
14     T *m_pT;
15     int m_maxsize;
16     int m_size;
17
18 };
19
20
21 template<class T, int maxsize> stackTest<T, maxsize>::stackTest()
22 {
23     m_maxsize = maxsize;
24     m_size = 0;
25     m_pT = new T[m_maxsize];
26 }
27
28 template<class T, int maxsize> stackTest<T, maxsize>::~stackTest()
29 {
30     delete[] m_pT;
31 }
32
33 template<class T, int maxsize> void stackTest<T, maxsize>::push(T t)
34 {
35     m_size++;
36     m_pT[m_size - 1] = t;
37 }
38
39 template<class T, int maxsize> T stackTest<T, maxsize>::pop()
40 {
41     T t = m_pT[m_size - 1];
42     m_size--;
43     return t;
44 }
45
46 template<class T, int maxsize> bool stackTest<T, maxsize>::isEmpty()
47 {
48     return m_size == 0;
49 }

stackTest.hpp

 1 // main.cpp
 2 #include <iostream>
 3 #include"stackTest.hpp"
 4
 5 using namespace std;
 6
 7 int main()
 8 {
 9     const int MAXSIZE = 200;
10     stackTest<int, MAXSIZE> tmpStack;
11
12     for (int i = 0; i < MAXSIZE; i++)
13     {
14         tmpStack.push(i);
15     }
16
17     while (!tmpStack.isEmpty())
18     {
19         cout << tmpStack.pop() << endl;
20     }
21
22     return 0;
23 }

main.cpp

  

  更多深入理解及记录稍后添加...

时间: 2024-10-29 19:11:31

C++模板总结的相关文章

Vue.js项目模板搭建

前言 从今年(2017年)年初起,我们团队开始引入「Vue.js」开发移动端的产品.作为团队的领头人,我的首要任务就是设计 整体的架构 .一个良好的架构必定是具备丰富的开发经验后才能搭建出来的.虽然我有多年的前端开发经验,但就「Vue.js」来说,仍然是个新手.所幸「Vue.js」有一个配套工具「Vue-CLI」,它提供了一些比较成熟的项目模板,很大程度上降低了上手的难度.然而,很多具体的问题还是要自己思考和解决的. 项目划分 我们公司的H5产品大部分是嵌套在手机客户端里面的页面.每个项目的功能

ac自动机基础模板(hdu2222)

In the modern time, Search engine came into the life of everybody like Google, Baidu, etc. Wiskey also wants to bring this feature to his image retrieval system. Every image have a long description, when users type some keywords to find the image, th

hdu 2966 In case of failure kdtree模板题

问求每个点距离平方的最小的点 kd-tree模板题…… 1 #include<bits/stdc++.h> 2 #define cl(a,b) memset(a,b,sizeof(a)) 3 #define debug(x) cerr<<#x<<"=="<<(x)<<endl 4 using namespace std; 5 typedef long long ll; 6 typedef pair<int,int>

eclipse添加xml模板

//因为学javaee,中框架,,感觉配置文件好多, window-preferences-xml-xmlfiles-editor-templates-选中模板,-edit

POJ3528 HDU3662 三维凸包模板

POJ3528 HDU3662 第一道题 给定若干点 求凸包的表面积,第二题 给定若干点就凸包的面数. 简单说一下三维凸包的求法,首先对于4个点假设不共面,确定了唯一四面体,对于一个新的点,若它不在四面体内,为了让它进入凸包, 则对于所有凸包上的边,若边的一面是该点可以看到的而另一面看不到,则该点与该边构成的面要加入凸包. 模板代码非常清晰, #include<stdio.h> #include<algorithm> #include<string.h> #includ

zabbix用自带的模板监控mysql

先看一下zabbix自带的mysql模板监控项: #很少是吧,没事生产环境一般我们不用,下一篇将介绍生产环境用的另一种mysql监控. 配置zabbix自带的模板监控mysql数据库:

小程序砸金蛋、外卖模板上线啦,快到酷客多商户后台更新!

最近,微信小程序官方发文不断,又开放十几项接口,逐步给企业主带来跟多福利.于此同时,酷客多研发团队也保持着一贯的研发和版本迭代速度,此次版本主要新增幸运砸金蛋.外卖模板.意见反馈三个模块 1.新增幸运砸金蛋,大奖中不停 通过此功能可增加平台趣味性,增强用户粘性,刺激用户二次消费,是与用户互动的一大利器. 2新增外卖模板,外卖送起来 此模板是餐饮企业的福利,可在注册或者酷客多商户管理后台直接选择此模板,瞬间让您的小程序首页变的高大上,从此再也不用担心第三方外卖平台高额的佣金和账期了,因为酷客多只提

C++学习笔记50:队列类模板

队列是只能向一端添加元素,从另一端删除元素的线性群体 循环队列 在想象中将数组弯曲成环形,元素出队时,后继元素不移动,每当队尾达到数组最后一个元素时,便再回到数组开头. 队列类模板 //Queue.h #ifndef QUEUE_H #define QUEUE_H #include <cassert> //类模板的定义 template <class T, int SIZE = 50> class Queue { private: int front, rear, count; T

ReactJS React+Redux+Router+antDesign通用高效率开发模板,夜间模式为例

工作比较忙,一直没有时间总结下最近学习的一些东西,为了方便前端开发,我使用React+Redux+Router+antDesign总结了一个通用的模板,这个技术栈在前端开发者中是非常常见的. 总的来说,我这个工程十分便捷,对于初学者来说,可能包含到以下的一些知识点: 一.React-Router的使用 Router是为了方便管理组件的路径,它使用比较简单,一般定义如下就行,需要注意的是,react-router的版本有1.0-3.0,各个版本对应的API大致相似,但也有不同,我使用的是2.X的,

Django的模板系统

模板系统介绍 模板系统的组成:HTML代码和逻辑控制代码 逻辑控制代码可以理解是django模板语言 django的模板语言组成 变量(使用双大括号来引用变量): 标签(tag)的使用(使用大括号和百分比的组合来表示使用tag) 模板继承 模板语言之变量 语法: {{var_name}} var_name 指变量名 使用模板语言之前: 先介绍template对象和Context对象 进入django的项目的交互环境 python manange.py shell >>> from dja