c++模版(c++学习笔记——模板和IO(一))
导读:前言...
前言
本文主要作为本人学习C\C++历程的的一种记录 ,以期望通过这种方式加深对知识点的记忆 ,查漏补缺 。如有写得不对的地方 ,欢迎大家批评改正 。
模板概论
模板是泛型编程的基础 ,是创建泛型类或函数的蓝图或公式 。
C++提供了两种模板机制:函数模板和类模板 。函数模板 ,实际上是建立了一个通用函数 ,其函数类型和形参类型不具体制定 ,用一个虚拟的类型来代表 。类模板和函数模板的定义和使用类似 。
下面开始逐一介绍C++模板的应用 。函数模板
定义函数模板
点击查看代码 template<class T> //注意:T代表泛型的数据类型 ,不是只能写T , void mySwap(T& a, T& b) { T temp = a; a = b; b = temp; }也可以这样定义函数模板
点击查看代码 template<typename T> void mySwap(T& a,T& b) { }怎么使用函数模板?
点击查看代码 template<class T> //注意:T代表泛型的数据类型 ,不是只能写T , void mySwap(T& a, T& b) { T temp = a; a = b; b = temp; } void test01() { int a = 10; int b = 20; mySwap(a, b); cout << "a = " << a << endl; cout << "b = " << b << endl; } //可以这样定义函数模板 //template<typename T> //void func(T a, T b) //{ // //} template<class T> T func1(T a, T b) { return a + b; } void test02() { int a = 10; double b = 20.3; //如果使用参数列表指定数据类型 ,那么实参中可以隐式转换, //如果转换成功 ,就调用 ,转换不成功就报错 cout << func1<int>(a, b) << endl; }普通函数和函数模板的区别
点击查看代码 //1.普通函数可以进行隐式转换,函数模版不能直接的进行隐性转换 //普通函数 int myPlus(int a, int b) { cout << "普通函数" << endl; return a + b; } //函数模板 template<class T> int myPlus(T a, T b) { cout << "函数模板" << endl; return a + b; } void test01() { int a = 10; double b = 20; myPlus(a, b); //普通函数可以进行隐性转换 //myPlus2(a, b); //没有与参数列表匹配的 函数模板 "myPlus2" 实例 myPlus<int>(a, b); //如果要进行隐性转换,必须加上参数列表 }普通函数和函数模板的调用规则
点击查看代码 //普通函数 int myPlus(int a, int b) { cout << "普通函数" << endl; return a + b; } //函数模板 template<class T> int myPlus(T a, T b) { cout << "函数模板" << endl; return a + b; } //函数模板重载 template<class T> void myPlus(T a, T b, T c) { cout << "函数模板myPlus(T a, T b, T c)" << endl; } //1 、函数模板和普通函数都可以重载 void test02() { int a = 10; int b = 20; //2 、如果普通函数和函数模板都可以实现的功能 ,普通函数优先调用 myPlus(a, b); //3 、可以使用<>空参数列表强制调用函数模板 myPlus<>(a, b); //4 、函数模板之间也可以进行重载 //5 、如果函数模板可以产生更好的匹配 ,那么优先使用函数模板 char c1 = a; char c2 = b; myPlus(c1, c2); }模板机制剖析——c++编译器是如何实现函数模板机制的?
编译器并不是把函数模板处理成能够处理任何类型的函数 函数模板通过具体类型产生不同的函数 编译器会对函数模板进行两次编译 ,在声明的地方对模板代码本身进行编译 ,在调用的地方对参数替换后的代码进行编译 。模板也具有局限性
点击查看代码 template<class T> void mycompare(T a, T b) { if (a > b) { cout << "a>b" << endl; } else { cout << "a<=b" << endl; } } void test01() { //如果传入的是数组名 ,那么函数模板中比较函数名的大小就没有意义 int arr[20]; int arr2[10]; mycompare(arr, arr2); }为解决上述问题 ,提出了两种方法
第一种:使用函数模板具体化 点击查看代码 class Maker { public: Maker(string name, int age) { this->name = name; this->age = age; } public: string name; int age; }; template<class T> void myfunc(T& a, T& b) { if (a > b) { cout << "a>b" << endl; } else { cout << "a<=b" << endl; } } //具体化函数模板 ,注意上面的函数模板要有 ,才能具体化 template<>void myfunc<Maker>(Maker& a, Maker& b) { cout << "函数模板的具体化" << endl; if (a.age > b.age) { cout << "a>b" << endl; } else { cout << "a<=b" << endl; } } 第二种:重载操作符 点击查看代码 class Maker1 { public: Maker1(string name, int age) { this->name = name; this->age = age; } public: string name; int age; }; bool operator>(Maker1& m1, Maker1& m2) { if (m1.name > m2.name && m1.age > m2.age) { return true; } else { return false; } } void test() { Maker1 a("aaa", 18); Maker1 b("bbb", 20); if (a > b) { cout << "a>b" << endl; } else { cout << "a<=b" << endl; } }定义类模板
点击查看代码 //类模板是把类中的数据类型参数化 template<class NameType,class AgeType> class Maker { public: Maker(NameType name, AgeType age) { this->name = name; this->age = age; } void printMaker() { cout << "Name:" << this->name << "Age:" << this->age << endl; } public: NameType name; AgeType age; };类模板的使用
点击查看代码 template<class NameType,class AgeType> class Maker { public: Maker(NameType name, AgeType age) { this->name = name; this->age = age; } void printMaker() { cout << "Name:" << this->name << "Age:" << this->age << endl; } public: NameType name; AgeType age; }; //类模板的使用 void test() { //1.类模版不会自动推导数据类型 ,要显示的告诉编译器是什么类型 Maker<string, int> m("高启强", 35); m.printMaker(); //2.注意传入的参数,传入参数类型要程序员自己把握 Maker<int, int>m2(18, 20); m2.printMaker(); //Maker<>m3("aaa", 18); //err:类模板“Maker"的参数太少 ,必须通过参数列表告诉编译器是什么类型 }类模板和函数模板的区别
类模板不会自动推导数据类型 ,要显示的告诉编译器是什么类型 函数模板可以根据实参来推导数据类型类模板的默认类型及其使用
点击查看代码 template<class NameType, class AgeType=int> class Maker2 { public: Maker2(NameType name, AgeType age) { this->name = name; this->age = age; } void printMaker() { cout << "Name:" << this->name << "Age:" << this->age << endl; } public: NameType name; AgeType age; }; void test02() { //如果有默认类型 ,那么<>里可以少写类型 Maker2<string> m("高启强", 35); //Maker2<string, int> m("高启兰", 20); m.printMaker(); //以传入的类型为准 Maker2<string, double> m2("高启盛", 24.22); m2.printMaker(); } //5 、类模板的默认参数注意 //默认类型后面的泛型类型都必须有默认类型 template<class NameType, class AgeType = int, class T = int> class Maker3 { public: Maker3(NameType name, AgeType age) { this->name = name; this->age = age; } void printMaker() { cout << "Name:" << this->name << " Age:" << this->age << endl; } public: NameType name; AgeType age; }; void test03() { Maker3<string> m("高启强", 35); m.printMaker(); }类模板做函数参数
点击查看代码 template<class NameType, class AgeType> class Maker { public: Maker(NameType name, AgeType age) { this->name = name; this->age = age; } void printMaker() { cout << "name = " << this->name << " " << " age = " << this->age << endl; } public: NameType name; AgeType age; }; //类模板做函数参数 //1.指定传入的数据类型 void func(Maker<string, int>& m) { m.printMaker(); } //2.参数模版化(常用) template<class T1, class T2> void func2(Maker<T1, T2>& m) { m.printMaker(); } //3.整个类 模版化 template<class T> void func3(T& m) { m.printMaker(); }类模板的继承
点击查看代码 //1 、普通类继承类模板 template<class T> class Father { public: Father() { m = 20; } public: T m; }; //普通类 继承 类模板 class Son : public Father<int> //2 、要告诉编译器父类的泛型数据类型具体是什么类型 { public: }; //2 、类模板 继承 类模板 //类模板 继承 类模板 template<class T1,class T2> class Son2 :public Father<T2> //要告诉编译器父类的泛型数据类型具体是什么类型 { };类模板的成员函数的类内实现
点击查看代码 template<class NameType,class AgeType> class Maker { public: Maker(NameType name, AgeType age) { this->name = name; this->age = age; } void printMaker() { cout << "Name:" << this->name << " " << "Age:" << this->age << endl; } public: NameType name; AgeType age; };类模板的成员函数类外实现
点击查看代码 template<class NameType,class AgeType> class Maker { public: Maker(NameType name, AgeType age); void printMaker(); public: NameType name; AgeType age; }; //类模板的成员函数类外实现 //成员函数必须写成函数模板,并且写上参数列表 template<class NameType,class AgeType> Maker<NameType,AgeType>::Maker(NameType name, AgeType age) { cout << "构造函数" << endl; this->name = name; this->age = age; } template<class NameType,class AgeType> void Maker<NameType, AgeType>::printMaker() { cout << "Name:" << this->name << " " << "Age:" << this->age << endl; }类模板的友元实现
类内实现 点击查看代码 template<class NameType,class AgeType> class Maker { friend void printMaker(Maker<NameType, AgeType>& p) { cout << "类内实现" <<" "<< p.name << " " << p.age << endl; } public: Maker(NameType name, AgeType age) { this->name = name; this->age = age; } private: NameType name; AgeType age; }; 类外实现 点击查看代码 //1 、声明模板 template<class NameType,class AgeType> class Maker2; //2 、声明函数模板 //告诉编译器下面有printMaker2的实现 template<class NameType,class AgeType> void printMaker2(Maker2<NameType, AgeType>& p); template<class NameType, class AgeType> class Maker2 { //3 、在函数名和()之间加上<> friend void printMaker2<>(Maker2<NameType, AgeType>& p); //编译器不知道printMaker2下面有没有实现 ,需要知道函数的结构 public: Maker2(NameType name, AgeType age) { this->name = name; this->age = age; } private: NameType name; AgeType age; }; //友元在类外实现要写成函数模板 template<class NameType,class AgeType> void printMaker2(Maker2<NameType, AgeType>& p) { cout << "类外实现的友元函数" << " "<<p.name << " " << p.age << endl; }类模板实现数组
MyArray.hpp
点击查看代码 #pragma once template<class T> class MyArray { public: MyArray(int capacity) { this->mCapacity = capacity; this->mSize = 0; //T如果是Maker ,这里要调用什么构造函数,要调用无参构造 p = new T[this->mCapacity]; } //拷贝构造 MyArray(const MyArray &arr) { this->mCapacity = arr.mCapacity; this->mSize = arr.mSize; p = new T[arr.mCapacity]; for (int i = 0; i < this->mSize; i++) { p[i] = arr.p[i]; } } //赋值函数 MyArray& operator=(const MyArray& arr) { if (this->p != NULL) { delete[] this->p; this->p = NULL; } p = new T[arr.mCapacity]; this->mSize = arr.mSize; this->mCapacity = arr.mCapacity; for (int i = 0; i < this->mSize; i++) { p[i] = arr.p[i]; } return *this; } //重载[] T& operator[](int index) { return this->p[index]; } //尾插 void Push_Back(const T& val) { if (this->mSize == this->mCapacity) { return; } this->p[this->mSize] = val; this->mSize++; } //尾删 void Pop_Back() { if (this->mSize == 0) { return; } this->mSize--; } //析构 ~MyArray() { if (this->p != NULL) { delete[] p; p = NULL; } cout << "析构函数" << endl; } int getSize() { return this->mSize; } private: T* p; int mCapacity; int mSize; };类模板实现数组.cpp
点击查看代码 #define _CRT_SECURE_NO_WARNINGS #include<string> #include<iostream> using namespace std; #include"MyArray.hpp" class Maker { public: Maker() { cout << "无参构造" << endl; } Maker(string name,int age) { this->name = name; this->age = age; } public: string name; int age; }; void printMaker(MyArray<Maker>& arr) { for (int i = 0; i < arr.getSize(); i++) { cout << "姓名:" << arr[i].name << " 年龄:" << arr[i].age << endl; } } void test() { //Maker类型 MyArray<Maker>myarr(4); Maker m1("小明", 18); Maker m2("小强", 19); Maker m3("小栋", 20); Maker m4("小兴", 21); myarr.Push_Back(m1); myarr.Push_Back(m2); myarr.Push_Back(m3); myarr.Push_Back(m4); printMaker(myarr); //int类型 MyArray<int>myint(10); for (int i = 0; i < 10; i++) { myint.Push_Back(i + 1); } for (int i = 0; i < 10; i++) { cout << myint[i] << " " << endl; } } int main() { test(); system("pause"); return EXIT_SUCCESS; }总结
模板是一个比较重要的概念 ,是创建泛型类或函数的蓝图或公式 。库容器 ,比如迭代器和算法 ,都是泛型编程的例子 ,它们都使用了模板的概念 。
-学习C++任重而道远 ,本人愚钝 ,唯有勤加练习方能查漏补缺 。创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!