1.Cpp中的模板template

  • 模板是泛型编程的基础,泛型编程即以一种独立于任何特定类型的方式编写代码。模板是创建泛型类或函数的蓝图或公式。库容器,比如迭代器和算法都是泛型编程的例子,它们都使用了模板的概念。每个容器都有一个单一的定义,比如向量vector可以定义许多不同类型的向量,如vector 或vector 。

2.函数模板

  • 函数模板定义的一般形式如下:

        template <typename 类型参数1, typename 类型参数2,...> 返回值类型 函数名(形参列表){// 在函数体中可以使用累成参数}
    
    • typename: 一个关键字,用来声明具体的类型参数。typename关键字也可以使用class关键字替代,它们没有任何区别。C++早期对模板的支持并不严谨,没有引入新的关键字,而是用 class来指明类型参数,但是class关键字本来已经用在类的定义中了,这样做显得不太友好,所以后来C++又引入了一个新的关键字 typename,专门用来定义类型参数。不过至今仍然有很多代码在使用class关键字,包括C++标准库、一些开源程序等。
    • template: 是定义函数模板的关键字,后面紧跟尖括号<>
    • 类型参数(也可以说是虚拟的类型,或者说是类型占位符): 模板头中包含的类型参数可以用在函数定义的各个位置,包括返回值、形参列表和函数体。类型参数的命名规则跟其他标识符的命名规则一样,不过使用T、T1、T2、Type等已经成为了一种惯例。
    • template: 模板头
  • 函数模板实例1如下:
        #include <iostream>using namespace std;// 函数模板template<typename T> void Swap(T &a, T &b){  // 此处的tyname关键字可以改成class!T temp;temp = a;a = b;b = temp;}int main(){// int类型变量交换int n1 = 200, n2 = 100;Swap(n1, n2);cout << "n1 = " << n1 << ", n2 = " << n2 << endl;// float类型变量交换float f1 = 3.14, f2 = 5.99;Swap(f1, f2);cout << "f1 = " << f1 << ", f2 = " << f2 << endl;return 0;}
    
  • 函数模板实例2如下:
        #include <iostream>using namespace std;// 函数模板的声明template<class T> T max(T a, T b, T c);int main(){// 求三个整数的最大值int i1, i2, i3, i_max;cout << "请依次输入三个整数: \n";cin >> i1 >> i2 >> i3;i_max = max(i1, i2, i3);cout << "i_max = " << i_max << endl;cout << "----------------------------------------------\n";// 求三个浮点数的最大值double d1, d2, d3, d_max;cout << "请依次输入三个浮点数: \n";cin >> d1 >> d2 >> d3;d_max = max(d1, d2, d3);cout << "d_max = " << d_max << endl;cout << "----------------------------------------------\n";return 0;}// 定义函数模板template<class T>   // 模板头,不能有分号T max(T a, T b, T c){  // 函数头T max_num = a;if( b > max_num)max_num = b;if(c > max_num)max_num = c;return max_num;}
    
  • 函数模板实例3如下:
        #include <iostream>#include "string"using namespace std;// 函数模板实例3template<class T> inline T const& Max(T const &a, T const &b){return a < b ? b:a;}int main(){int i = 20, j = 30;cout << "Max(i, j) = " << Max(i, j) << endl;double db1 = 23.4, db2 = 44.9;cout << "Max(db1, db2) = " << Max(db1, db2) << endl;string s1 = "hello", s2 = "world";cout << "Max(s1, s2) = " << Max(s1, s2) << endl;return 0;}
    

3.类模板

  • C++除了支持函数模板,还支持类模板(Class Template)。函数模板中定义的类型参数可以用在函数声明和函数定义中,类模板中定义的类型参数可以用在类声明和类实现中,类模板的目的同样是将数据的类型参数化。一但声明了类模板,就可以将类型参数用于类的成员函数和成员变量了。换句话说,原来使用int、float、char等内置类型的地方,都可以用类型参数来代替。
  • 声明类模板的语法为:
        template <typename 类型参数1, typename 类型参数2,...> class 类名{//TODO;}
    
  • 类模板中类的声明如下:
        template<typename T1, typename T2>  // 这里不能有分号!!!class Point{public:Point(T1 x, T2 y): m_x(x), m_y(y){cout << "构造函数\n";}public:T1 getX() const;  // 常函数void setX(T1 x);  T2 getY() const;void setY(T2 y);private:T1 m_x;T2 m_y;};
    
  • 上面的代码仅仅是类的声明,我们还需要在类外定义成员函数。在类外定义成员函数时仍然需要带上模板头,格式为:
        template<typename 类型参数1, typename 类型参数2,...> 返回值类型 类名<类型参数1, 类型参数2,...>::函数名(形参列表){TODO;}
    
  • 类模板中的成员函数定义如下:
        // 类外成员函数的定义template<typename T1, typename T2>  // 模板头T1 Point<T1, T2>::getX() const{  // 函数头return m_x;} template<typename T1, typename T2>void Point<T1, T2>::setX(T1 x){m_x = x;}template<typename T1, typename T2>T2 Point<T1, T2>::getY() const{return m_y;}template<typename T1, typename T2>void Point<T1, T2>::setY(T2 y){m_y = y;}
    
    • 仔细观察代码,除了 template 关键字后面要指明类型参数,类名Point后面也要带上类型参数,只是不加typename关键字了。另外需要注意的是,在类外定义成员函数时,template后面的类型参数要和类声明时的一致。

4.使用类模板创建对象

  • 上面的两段代码完成了类的定义,接下来就可以使用该类创建对象了。使用类模板创建对象时,需要指明具体的数据类型。请看下面的代码:

        Point<int, int> p1(10, 20);Point<int, float> p2(10, 5.5);Point<float, char*> p3(4.3, "hello");
    
  • 与函数模板不同的是,类模板在实例化时必须显式地指明数据类型,编译器不能根据给定的数据推演出数据类型
  • 除了对象变量,我们也可以使用对象指针的方式来实例化:
        Point<float, float> *p1 = new Point<float, float>(10.6, 90.3);Point<char*, char*> *p2 = new Point<char*, char*>("hello", "world");
    
  • 需要注意的是,赋值号两边都要指明具体的数据类型,且要保持一致。下面的写法是错误的:
        // 赋值号两边的数据类型不一致Point<float, float> *p = new Point<float, int>(10.6, 109);// 赋值号右边没有指明数据类型Point<float, float> *p = new Point(10.6, 109);
    
  • 综合实例1如下:
        #include <iostream>using namespace std;template<class T1, class T2>  //这里不能有分号class Point{public:Point(T1 x, T2 y): m_x(x), m_y(y){ }public:T1 getX() const;  //获取x坐标void setX(T1 x);  //设置x坐标T2 getY() const;  //获取y坐标void setY(T2 y);  //设置y坐标private:T1 m_x;  //x坐标T2 m_y;  //y坐标};template<class T1, class T2>  //模板头T1 Point<T1, T2>::getX() const /*函数头*/ {return m_x;}template<class T1, class T2>void Point<T1, T2>::setX(T1 x){m_x = x;}template<class T1, class T2>T2 Point<T1, T2>::getY() const{return m_y;}template<class T1, class T2>void Point<T1, T2>::setY(T2 y){m_y = y;}int main(){Point<int, int> p1(10, 20);cout<<"x="<<p1.getX()<<", y="<<p1.getY()<<endl;Point<int, char*> p2(10, "东经180度");cout<<"x="<<p2.getX()<<", y="<<p2.getY()<<endl;Point<char*, char*> *p3 = new Point<char*, char*>("东经180度", "北纬210度");cout<<"x="<<p3->getX()<<", y="<<p3->getY()<<endl;return 0;}
    
  • 类模板综合实例2如下:
        template <class T>class CArray{private:int size; // 数组的大小T *ptr;   // 指向动态数组的指针public:CArray(int s = 0); // 构造函数CArray(CArray &a); // 拷贝构造函数~CArray();         // 析构函数void push_back(const T &v);         //用于在数组的尾部添加一个元素CArray &operator=(const CArray &a); // 运算符重载,用于数组对象间的重载// 注意下面的两个函数已经定义过了T length(){return size;}T &operator[](int i){return ptr[i]; // 用以支持根据下标访问数组元素}};// 类成员函数的定义template <class T>CArray<T>::CArray(int s) : size(s){if (s == 0)ptr = NULL;elseptr = new T[s];}template <class T>CArray<T>::CArray(CArray &a){if (!a.ptr){ptr = NULL;size = 0;return;}ptr = new T[a.size];memcpy(ptr, a, ptr, sizeof(T) * a.size);size = a.size;}template<class T>CArray<T>::~CArray(){if(ptr)delete [] ptr;}template <class T>CArray<T> &CArray<T>::operator=(const CArray &a){if (this == &a) //防止a=a这样的赋值导致出错, 赋值号的作用是使"="左边对象里存放的数组,大小和内容都和右边的对象一样return *this;if (a.ptr == NULL){ // 如果a里面的数组是空的if (ptr)delete[] ptr;ptr = NULL;size = 0;return *this;}if (size < a.size){ // 如果原有空间够大,就不用分配新的空间if (ptr)delete[] ptr;ptr = new T[a.size];}memcpy(ptr, a.ptr, sizeof(T) * a.size);return *this;}template <class T>void CArray<T>::push_back(const T &v){ //在数组尾部添加一个元素if (ptr){T *tmpPtr = new T[size + 1];           // 重新分配空间memcpy(tmpPtr, ptr, sizeof(T) * size); // 拷贝原数组内容delete[] ptr;ptr = tmpPtr;}else // 数组本来是空的ptr = new T[1];ptr[size++] = v; // 加入新的数组元素}int main(){CArray<int> a;for(int i =0; i < 5;i++)a.push_back(i);for(int i=0; i < a.length(); i++)cout << "a[" << i << "] = " << a[i] << endl;return 0;}
    

C++中的模板template相关推荐

  1. Tornado框架中视图模板Template的使用

    上文的程序中有这样一段: class MessageHandler(tornado.web.RequestHandler):def get(self):self.write(''' <html& ...

  2. C++中函数模板template和函数参数为指针,且有返回值的结合使用

    1 #include<iostream> 2 using namespace std; 3 // 利用模板函数计算一个表达式 4 template<class Type> 5 ...

  3. 模板template

    这个是C++中的模板..template<typename T> 这个是定义模板的固定格式 模板应该可以理解到它的意思吧.. 比如你想求2个int float 或double型变量的值,只 ...

  4. ES6, Angular,React和ABAP中的String Template(字符串模板)

    String Template(字符串模板)在很多编程语言和框架中都支持,是一个很有用的特性.本文将Jerry工作中使用到的String Template的特性做一个总结. ES6 阮一峰老师有一个专 ...

  5. Vue中 模板template的四种写法

    <div id="app"><h1>我是直接写在构造器里的模板1</h1> </div><template id=" ...

  6. T4((Text Template Transformation Toolkit))模版引擎之基础入门 C#中文本模板(.tt)的应用...

    1 关于C#中文本模板(.tt)的简单应用 https://blog.csdn.net/zunguitiancheng/article/details/78011145 任何一个傻瓜都能写出计算机能理 ...

  7. 微信小程序模板template

    上面是官方的讲解, 主要是方便在不同的地方调用. 下面自己说下使用, 先创建一个模板名字是自己随便取的, 在template.wxml中填写模板 最外层用template标签 设置一个name属性 & ...

  8. C++中标准模板库std::vector的实现

    以下实现了C++标准模板库std::vector的部分实现,参考了 cplusplus. 关于C++中标准模板库std::vector的介绍和用法可以参考 https://blog.csdn.net/ ...

  9. OpenCV中使用模板匹配识别空闲的货架空间

    但是点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 假设你是一名在超市工作的员工,被要求在商店里四处走动,检查需要 ...

最新文章

  1. 洛谷 P1966 火柴排队
  2. python中类的定义方法_python中类的定义方法
  3. paddleocr ‘bytes‘ object has no attribute ‘shape‘
  4. [AS3][Matrix][利用颜色矩阵进行颜色变换]
  5. 柱底反力求和lisp软件_AutoLISP详细讲解
  6. 1000瓶药水,1瓶有毒药,几只小白鼠能够找出毒药
  7. 什么是ooa,oop
  8. Apache 2 移植到Arm开发板
  9. 【排序算法】冒泡排序的三种方法
  10. win10+Ubuntu16.04 LTS双系统完美教程
  11. 下载代码的两种方式ssh 和 https
  12. 运维工程师面试题(1)
  13. VMare虚拟机无法识别USBkey问题
  14. 计算机网络 ping中ttl,ping命令TTL什么意思 ping值ttl多少算正常
  15. 小度wifi linux ap,小度WiFi的频率范围是多少
  16. 浩瀚先森(guohao1206.com)
  17. MM们必败潮物。。。。大眼睛的小秘密哦```````
  18. marvell 88W8686 sdio wifi模块学习
  19. 人工智能要学习哪些数学知识?
  20. JavaScript 控制(改变)canvas(画布)的大小

热门文章

  1. pinpoint zipink skywalking
  2. Redis数据类型:散列类型
  3. javascript-数据类型,json与数组,获取非行间样式
  4. MySQL排错工具perror
  5. 给字符数组赋值的方法
  6. Beyond MySQL --Branching the popular database--转载
  7. 请大佬们多给运维人员思考和决策的权利
  8. 谈谈架构的本质和架构分类
  9. 农行数据中台建设与应用实践
  10. Stackoverflow 高赞答案,为什么牛逼的程序员都不用 “ ! = null ' 做判空?