C++模板

模板编程也叫泛型编程,忽略数据类型的一种编程

template<class Type1,class Type2,...>
// class 和typename效果一样的

总体介绍

  • 学会模板基本

    • 函数模板
    • 类模板
  • 标准中模板类(STL)
    • 容器—>数据结构
    • 迭代器—>遍历容器
    • 仿函数—>描述关系
    • 算法—>各种基本算法

简单模板

#include<iostream>
#include<string>
using namespace std;
//int Max(int a, int b)
//{
//  return a > b ? a : b;
//}
//string Max(string a, string b) {
//  return a > b ? a : b;
//}
//double Max(double a, double b) {
//  return a > b ? a : b;
//}
template<class Type>              // template <typename Type>等效的
Type Max(Type a, Type b) {return a > b ? a : b;
}int main() {cout << Max(string("yxc"), string("xc")) << endl;      // Type = stringcout << Max(1, 2) << endl;                             // Type = intreturn 0;
}

函数模板

  • 两个模板都能使用,优先调用未知类型少
  • 显示调用百分百调用函数模板
  • 隐式调用 优先调用匹配到的普通函数
#include<iostream>
#include<string>
using namespace std;// No.1模板的调用过程
// 一般情况  自己想要用到几个未知类型就定义几个
template<class _Ty1,class _Ty2,class _Ty3>
void print(_Ty1 one, _Ty2 two, _Ty3 three)
{cout << "print:" << endl;cout << one << endl;    // _Ty1=YXC  cout<<yxcObject<<endl;cout << two << endl;cout << three << endl;
}
void testCall()
{cout << "testCall:" << endl;// 隐式调用// 常量的自动推断是: const char*print(string("123"), 1, 1.1);   // 自动推断类型 _Ty1=string _Ty2=int _Ty3=dboule// 显示调用:传入的类型需要和数据保持一致// 函数名<传入类型>(参数)print<double, double, double>(1.11, 2.22, 3);// print<double,double,double>(1.11,2.22,string("yxcyxc"));print<string, int, string>(string("string"), 1, string("yxc"));
}// No.2 函数模板操作自定义类型
class YXC
{
public:YXC(string name,int age):name(name),age(age){}friend ostream& operator<<(ostream& out, const YXC& object) {out << object.name << "\t" << object.age;return out;}
protected:string name;int age;
};void testUserData()
{cout << endl << endl;cout << "testUserData:"<<endl;// 使用别人的模板,最大的问题就是重载YXC object("yxc", 20);print(object, 1, 2);
}// No.3 函数模板的另一个形态
class Boy
{
public:template<typename _Ty1>void print(_Ty1 one);
protected:
};template <typename _Ty1> void Boy::print(_Ty1 one)
{cout << one << endl;
}
void classFunc() {cout << endl;cout << "classFunc:" << endl;Boy boy;boy.print("yxcYYDS");
}// No.4 函数模板的重载
// 思考问题的隐式调用调用是哪个函数
template <typename _Ty1,typename _Ty2>
void printData(_Ty1 one, _Ty2 two) {cout << "两个未知类型" << endl;cout << one << endl;cout << two << endl;
}
template <class _Ty1>
void printData(_Ty1 one, _Ty1 two)
{cout << "一个未知类型" << endl;cout << one << endl;cout << two << endl;
}
template <typename _Ty1>
void printData(_Ty1 one)
{cout << "一个:" << endl;cout << one << endl;
}
void printData(int data)
{cout << "普通函数" << endl;cout << data << endl;
}
void testFunc()
{cout << endl << endl;cout << "testFunc:";printData(1, 2);              // 两个模板都能使用,优先调用未知类型少的那个printData(1, string("2"));     // 只适用于第一个printData<int>(1);              // 显示调用百分百调用函数模板printData(22);                  // 隐式调用  优先调用匹配到的普通函数
}
// No.5 函数模板也是传参,所以也可以缺省
template<class _Ty1=int>
void printNum(_Ty1 one)
{cout << one << endl;
}
void testCallNum() {cout << endl << endl;cout << "testCallNum:";printNum(1);printNum(1.11);printNum(string("yxc"));printNum<>(2333);printNum<string>(string("string"));
}// No.6 模板含变量情况
template <class _Ty1,size_t size>
void NewMemory(_Ty1*& p)
{p = new _Ty1[size];
}void testNew()
{cout << endl << endl;cout << "testNew:";int* p = nullptr;NewMemory<int, 3>(p);p[0] = 1;cout << p[0];char* pstr = nullptr;NewMemory<char,10>(pstr);strcpy_s(pstr, 10, "ILoveyou");cout << pstr << endl;// 错误写法,只能传入常量// const int size = 10;// int* pp = nullptr;// NewMemory<int,size>(pstr);
}int main()
{testCall();testUserData();classFunc();testFunc();testCallNum();testNew();return 0;
}

类模板

  • 类模板不是一个完整类,所有用到类型的地方,必须要 :类名<未知类型>
  • 类模板必须要用显示调用方式,不能隐式
  • 多文件中类模板不能分开写,必须写在一个文件中 ,xxx.hpp
#include<iostream>
#include<array>
using namespace std;// 类模板
// No.1 类模板的写法
// 1.1类模板不是一个完整的类,所有用到类型的地方,必须要:类名<未知类型>
// 2.2类模板必须要用显示调用的方式,不能隐式
// 2.3多文件中类模板不能分开写,必须写在一个文件中,xxx.hpp
template <class _Ty1,class _Ty2>
struct my_pair
{_Ty1 first;_Ty2 second;my_pair(_Ty1 first, _Ty2 second);void print(){cout << first << endl;cout << second << endl;}
};
template <class _Ty1,class _Ty2>
my_pair<_Ty1, _Ty2>::my_pair(_Ty1 first,_Ty2 second):first(first),second(second)
{cout << "所有用到类型的地方都要用类型<未知类型>" << endl;
}
template <class _Ty1>
class YXC
{
public:YXC(_Ty1 data):data(data){}
protected:_Ty1 data;
};
template <class _Ty1>
class Boy :public YXC<_Ty1>
{
public:Boy(_Ty1 data):YXC<_Ty1>(data){}
protected:
};// No.2 模板类中的静态数据成员
template <class _Ty1>
class Test
{
public:static int data;
};template <class _Ty1>
int Test<_Ty1>::data = 123;
// Noo.3 类模板也可以传入变量
template <class _Ty,size_t length>
class my_vector
{
public:my_vector(){max = length;pData = new _Ty[length];curSize = 0;}void push_back(_Ty data){pData[curSize++] = data;}int size() const{return max;}_Ty& operator[](int index){if (index < 0 || index >= max){throw "length_error";}return pData[index];}
protected:_Ty* pData;int curSize;int max;
};
void test_array()
{my_vector<int, 5> array;for (int i = 0; i < array.size(); i++){array.push_back(i);}for (int i=0;i<array.size();i++){cout << array[i] << "\t";}cout << endl;
}
// No.4 类模板的特化问题
template<class _Ty1,class _Ty2>
class Data
{
public:Data(_Ty1 one, _Ty2 two):one(one),two(two){cout << "原生模板" << endl;}
protected:_Ty1 one;_Ty2 two;
};
// 局部特化-->特殊化处理
template<class _Ty>
class Data<_Ty, _Ty>
{
public:Data(_Ty one, _Ty two) :one(one), two(two){cout << "局部特化" << endl;}
protected:_Ty one;_Ty two;
};
// 完全特化-->类型具象化
// 为了`针对特定数据做特定处理
template<>
class Data<int, string>
{
public:Data(int one, string two) :one(one), two(two){cout << "完全特化" << endl;}
protected:int one;string two;
};void testData()
{Data<int, int >  data1(1, 1);Data<int, string> data2(1, string("yxc"));Data<string, int> data3(string("yxcyxc"), 23333);
}int main() {my_pair<int, string> object(1, string("模板"));object.print();my_pair<int, string>* p = new my_pair<int, string>(2, string("YXCYXC"));p->print();Boy<int> boy(1);cout << Test<int>::data << endl;test_array();testData();return 0;
}

类模板的嵌套

#include<iostream>
using namespace std;
template <class _Ty1,class _Ty2>
class Test
{
public:Test(){cout << "Test默认无参构造函数1" << endl;cout << one << "   "  << two <<  "   "  << endl;}Test(_Ty1 one, _Ty2 two) : one(one), two(two){cout << "Test有参构造函数1" << endl;cout << one <<  "   "   << two <<  "   "  << endl;}friend ostream& operator<<(ostream& out, Test& object){out << object.one << endl;out << object.two << endl;return out;}
protected:_Ty1 one;_Ty2 two;
};
template<class _Ty1,class _Ty2,class _Ty3>
class Data
{
public:Data(){cout << "Data默认无参构造函数2" << endl;cout << one <<  "   "  << two <<  "   "  << three << endl;};Data(_Ty1 one, _Ty2 two, _Ty3 three) :one(one), two(two), three(three){cout << "Data有参构造函数2" << endl;cout << one <<  "   "   << two <<  "   "   << three << endl;}friend ostream& operator<<(ostream& out, Data& object){out << object.one << endl;out << object.two << endl;out << object.three << endl;return out;}
protected:_Ty1 one;_Ty2 two;_Ty3 three;
};int main()
{Data<Test<int,int>,Test<string,string>,Test<int,string>> data1;cout << "-----------------------" << endl;Data<Test<int, int>, Test<string, string>, Test<int, string>>data11(Test<int,int>(1,2),Test<string,string>("YXC","yxc"),Test<int,string>(1,"xc"));cout << "-----------------------" << endl;Data<Test<int, Data<int, int, int>>, int, string> data2;cout << "-----------------------" << endl;Data<Test<int, Data<int, int, int>>, int, string>data22(Test<int, Data<int, int, int>>(1, Data<int, int, int>(1, 1, 1)), 1, "yxcYYDS");cout << "-----------------------" << endl;// 简化:起别名的方式using Type1 = Test<int, int>;using Type2 = Test<string, string>;using Type3 = Test<int, string>;Data<Type1, Type2, Type3> usingData11(Type1(1, 2), Type2("YXC", "yxc"), Type3(1, "yxcYYDS"));return 0;
}

封装模板链表

  • 直接上代码
#include<iostream>
#include<string>
#include<list>
using namespace std;
template <class _Ty>
struct Node
{_Ty data;Node<_Ty>* next;Node(_Ty data) :data(data),next(nullptr){}
};
template <class _Ty>
class List
{
public:List();void push_back(_Ty data);void push_front(_Ty data);void pop_back();void pop_front();int size() const;bool empty() const;_Ty front() const;_Ty back() const;void printList();Node<_Ty>* begin(){return frontNode;}Node<_Ty>* end(){return nullptr;}
public:// 类中类访问数据class iterator{public:void operator=(Node<_Ty>* pmove){this->pmove = pmove;}bool operator!=(Node<_Ty>* pmove){return this->pmove != pmove;}void operator++(){pmove = pmove->next;}_Ty operator*(){return pmove->data;}protected:Node<_Ty>* pmove;};
protected:Node<_Ty>* frontNode;Node<_Ty>* backNode;int curSize;
};template<class _Ty>
List<_Ty>::List()
{frontNode = nullptr;backNode = nullptr;curSize = 0;
}template<class _Ty>
inline void List<_Ty>::push_back(_Ty data)
{Node<_Ty>* newNode = new Node<_Ty>(data);if (curSize == 0){frontNode = newNode;// backNode = newNode}else{backNode->next = newNode;// backNode = newNode;}backNode = newNode;curSize++;
}template<class _Ty>
inline void List<_Ty>::push_front(_Ty data)
{Node<_Ty>* newNode = new Node < _Ty>(data);if (curSize == 0){// fontNode = newNode;backNode = newNode;}else{newNode->next = frontNode;// frontNode = newNode;}frontNode = newNode;curSize++;
}template<class _Ty>
inline void List<_Ty>::pop_back()
{if (curSize == 1){delete frontNode;frontNode = nullptr;backNode = nullptr;}else{Node<_Ty>* pmove = frontNode;while (pmove->next->next != nullptr){pmove = pmove->next;}delete pmove->next; // ==delete backNode;pmove->next = nullptr;backNode = pmove;}curSize--;
}template<class _Ty>
inline void List<_Ty>::pop_front()
{if (curSize == 1){delete frontNode;frontNode = nullptr;backNode = nullptr;}else{Node<_Ty> nextNode = frontNode->next;delete frontNode;frontNode = nextNode;}curSize--;
}template<class _Ty>
inline int List<_Ty>::size() const
{return curSize;
}template<class _Ty>
inline bool List<_Ty>::empty() const
{return curSize == 0;
}template<class _Ty>
inline _Ty List<_Ty>::front() const
{return frontNode->data;
}template<class _Ty>
inline _Ty List<_Ty>::back() const
{return backNode->data;
}template<class _Ty>
inline void List<_Ty>::printList()
{Node<_Ty>* pmove = frontNode;while (pmove != nullptr){cout << pmove->data;pmove = pmove->next;}cout << endl;
}class YXC
{
public:YXC(string name,int age) :name(name),age(age){}friend ostream& operator<<(ostream& out, const YXC& object){out << object.name << "\t" << object.age << endl;return out;}
protected:string name;int age;
};
int main()
{List<int> iList;iList.push_back(1);iList.push_back(2);iList.push_front(3);iList.printList();iList.pop_back();iList.printList();iList.push_back(2);// 通过类中类打印数据List<int>::iterator iteri;for (iteri = iList.begin(); iteri != iList.end(); ++iteri){cout << *iteri << "\t";}cout << endl;List<string> sList;sList.push_back("First_YXC");sList.push_back("Second_YXC");sList.push_back("Third_YXC");sList.printList();// 通过类中类打印数据List<string>::iterator iters;for (iters = sList.begin(); iters != sList.end(); ++iters){cout << *iters << "\t";}cout << endl;List<YXC> yxcList;yxcList.push_back(YXC("18岁的YXC",18));yxcList.push_back(YXC("19岁的YXC", 19));yxcList.push_back(YXC("20岁的YXC", 20));yxcList.printList();// 通过类中类打印数据List<YXC>::iterator iter;for (iter = yxcList.begin(); iter != yxcList.end(); ++iter){cout << *iter;}// 标准库里的listlist<YXC> test;test.push_back(YXC("18的yxc",18));test.push_back(YXC("19的yxc",19));test.push_back(YXC("20的yxc",20));// 通过类中类打印数据list<YXC>::iterator itertest;for (itertest = test.begin(); itertest != test.end(); ++itertest){cout << *itertest;}return 0;
}

C++模板/泛型编程相关推荐

  1. C++ 泛型编程(一):模板基础:函数模板,类模板,模板原理,模板匹配规则

    类模板 函数模板 泛型编程 泛型编程,泛型即是指具有在多种数据类型上皆可操作的含义,其实就是能够帮助开发者编写完全一般化并可重复使用的算法,同样的工作不需要做多次,同样的算法针对不同的类型也不应该写多 ...

  2. C++11新特性之泛型编程与模板

    模板 泛型编程 函数模板 普通函数模板 成员函数模板 函数模板重载 模板函数的特化 类模板 类模板中的成员函数模板 类模板的特化与偏特化 类模板成员特化 模板 Template所代表的泛型编程是C++ ...

  3. C++ 模板偏特化-来自STL的思考

    之前学习STL时接触过一段时间的模板,模板是C++泛型编程编程的基础 STL从头到尾都是模板泛型编程,我觉得用的最巧妙的就是在traits萃取技巧时用到的模板偏特化 先简要回顾一下模板吧,模板主要分为 ...

  4. C++模板剖析:函数模板、类模板解析

    C++中关于模板&泛型编程问题:   问题引入:何编写一个通用加法函数? (1)使用函数重载,针对每个所需相同行为的不同类型重新实现它 int Add(const int &_iLef ...

  5. 【转载】JAVA的泛型和C++的模板的区别与联系

    一.概述 泛型本质上是提供类型的"类型参数",它们也被称为参数化类型(parameterized type)或参量多态(parametric polymorphism).其实泛型思 ...

  6. c++模板类声明和定义的问题

    这里在学习的过程中遇到的一些问题,比较简单,但还是记下来,以免下次遇到这个问题再犯,大佬们可跳过哦.先简单的介绍下模板的概念 C++模板(泛型编程) c++模板是泛型编程的基础,所谓泛型编程也是一种思 ...

  7. C++ STL标准模板库简介

    文章目录 1. 什么是STL? 2. STL的优势 3. STL版本? 4. STL的六大组件 5. 学习建议 6. 为什么需要迭代器? 7. 自己实现迭代器iterator 8. STL中的5种迭代 ...

  8. C++模板——模板特化、分离编译

    这里写目录标题 一.泛型编程与模板 二.函数模板 1.概念 2.原理 3.函数模板的实例化 3. 模板实现复数类的加法 4.模板参数的匹配原则 三.类模板 1.定义格式 用类模板实现顺序表 2.非类型 ...

  9. C++内存管理+模板入门知识点

    内存管理+模板 内存管理 C C++ 内置类型 自定义类型 内存泄漏 模板 泛型编程 函数模板 模板参数匹配原则 类模板 内存管理 C malloc(); free(); C++ new delete ...

最新文章

  1. 洛谷 P1029 最大公约数和最小公倍数问题
  2. python遍历目录压缩文件夹然后在发送邮件_python目录操作之python遍历文件夹后将结果存储为xml...
  3. 数据仓库与数据集市建模
  4. 【风险管理】金融产品一站式解决方案
  5. C++11:委托构造函数
  6. 大数据计算存储资源池_管家实践:轻松玩转大数据计算服务
  7. Bailian2952 循环数【数学】
  8. python3 datatime,python3处理时间和日期:datetime模块 – Python3教程
  9. python字符串创建_python独特的字符串创建
  10. window核心编程 22.3 DIPS.exe的踩坑逻辑梳理
  11. Python的m3u8下载器源码
  12. helm和operator
  13. 【Python习题】计算弓形的面积(保姆级图文+实现代码)
  14. 【1044】判断是否为两位数
  15. virtualBox安装GHO镜像
  16. eeglab中文教程系列(1)-加载、显示数据
  17. 2021-2027全球及中国合成孔径雷达卫星服务行业研究及十四五规划分析报告
  18. 说说wordpress博客的安全防护
  19. python编辑svg文件_使用Python批量转换SVG文件为PNG或PDF文件
  20. ASP.NET画文字验证码

热门文章

  1. 鱼眼图像校正(球面等距投影模型)
  2. 软件版本alpha、beta、gamma等
  3. Php 波场离线签名 Tron离线签名
  4. 餐饮店选址要考虑竞品分布,用户画像等
  5. python矩阵和向量乘积_矩阵与向量的乘积
  6. ogr2ogr转坐标
  7. linux 计费服务器,腾讯云服务器的实例计费问题
  8. c语言编写英语词典软件,C语言课程设计一种简单的英文词典排版系统的实现.doc...
  9. s18服务器维护,8月11日S15至S18服务器合服公告!
  10. 【学习笔记】李宏毅2021春机器学习课程第6.2节:生成式对抗网络 GAN(二)