直接上代码举个栗子:
#include <iostream> template<typename t> void myswap(t& a, t& b) { t temp = a; a = b; b = temp; } template<typename t> void mysort(t arr[], int len) { for (int i = 0; i <= len; i++) { int max = i; for (int j = i + 1; j <= len; j++) { if (arr[j] > arr[max]) { max = j; } } if (max != i) { myswap(arr[max],arr[i]); } } } template<typename t> void print(t arr[], int len) { for (int i = 0; i < len; i++) { std::cout << arr[i]<<" "; } std::cout << std::endl; } int main(void) { /*int a = 5, b = 10; double c = 6.6, d = 9.9; myswap(a, b); myswap(c, d); std::cout << "a:" << a << std::endl; std::cout << "b:" << b << std::endl; std::cout << "c:" << c << std::endl; std::cout << "d:" << d << std::endl;*/ char a[] = "adwascf"; int len = sizeof(a) / sizeof(char); mysort(a, len); print(a, len); int b[] = {1,5,9,6,4,2,7}; int len_ = sizeof(b) / sizeof(int); mysort(b, len_); print(b, len_); return 0; }
类模板
继续上代码:
#include <iostream> #include <vector> #include <cstdlib> #include <string> #include <stdexcept> using namespace std; template <class T> class Stack { private: vector<T> elems; // 元素 public: void push(T const&); // 入栈 void pop(); // 出栈 T top() const; // 返回栈顶元素 bool empty() const { // 如果为空则返回真。 return elems.empty(); } }; template <class T> void Stack<T>::push(T const& elem) { // 追加传入元素的副本 elems.push_back(elem); } template <class T> void Stack<T>::pop() { if (elems.empty()) { throw out_of_range("Stack<>::pop(): empty stack"); } // 删除最后一个元素 elems.pop_back(); } template <class T> T Stack<T>::top() const { if (elems.empty()) { throw out_of_range("Stack<>::top(): empty stack"); } // 返回最后一个元素的副本 return elems.back(); } int main() { try { Stack<int> intStack; // int 类型的栈 Stack<string> stringStack; // string 类型的栈 // 操作 int 类型的栈 intStack.push(7); cout << intStack.top() << endl; // 操作 string 类型的栈 stringStack.push("hello"); cout << stringStack.top() << std::endl; stringStack.pop(); stringStack.pop(); } catch (exception const& ex) { cerr << "Exception: " << ex.what() << endl; return -1; } }
类模板与函数模板区别
1.函数模板可以自动类型转换,而类模板必须指明
2.类模板可以有默认参数
3.类模板中的成员方法,在调用时才会去生成(因此在分文件编写时会出错,有两种解决方案:
1.不能用".h"而是".cpp",即先让编译器看源文件
2.将.h和.cpp中的内容写在一起,创建一个".hpp"(约定俗成,指模板文件)的文件)
类模板实例化对象作参数传递给函数
#include< iostream> #include<string> //using namespace std; template<class T1, class T2> class Person{ public: Person(T1 name, T2 age) { this->m_Name = name; this->m_Age = age; } void showPerson() { std::cout << "姓名:" << this->m_Name << " 年龄:" << this->m_Age << std::endl; } T1 m_Name; T2 m_Age; }; //直接指定 void printPerson_1(Person<std::string,int> &p) { p.showPerson(); } void test01() { Person<std::string, int> p("孙悟空", 99); printPerson_1(p); } //参数模板化 template<class T1, class T2> void printPerson_2(Person<T1, T2>& p) { p.showPerson(); std::cout << "T1的类型为:" << typeid(T1).name() << std::endl; std::cout << "T2的类型为:" << typeid(T2).name() << std::endl; } void test02() { Person<std::string, int> p("猪八戒", 90); printPerson_2(p); } //整个类模板化 template<class T> void printPerson_3(T &p) { p.showPerson(); std::cout << "T的类型为:" << typeid(T).name() << std::endl; } void test03() { Person<std::string, int> p("唐僧", 30); printPerson_3(p); } int main(void) { test01(); test02(); test03(); return 0; }
使用较多的还是第一种:直接指定
#include<iostream> template<class T> class Base { T m; }; //class Son:public Base { 报错!只有知道父类中T的类型,才能继承给子类 class Son1:public Base<int>{ }; void test01() { Son1 s1; } //如果想让子类灵活继承父类中T类型,那子类也需要变成类模板 template<class T1, class T2> class Son2 :public Base<T2> { T1 obj; public: Son2() { std::cout << "T1的类型为:" << typeid(T1).name() << std::endl; std::cout << "T2的类型为:" << typeid(T2).name() << std::endl; } }; void test02() { Son2<int, char> s2; } int main(void) { test01(); test02(); return 0; }
本质上是子类继承是类模板的基类,需要子类自己指定T的数据类型
类模板函数类外实现
#include<iostream> #include<string> template<class T1, class T2> class Person { public: Person(T1 name, T2 age); void showPerson() { std::cout << "姓名:" << this->m_Name << " 年龄:" << this->m_Age << std::endl; } T1 m_Name; T2 m_Age; }; template<class T1, class T2> Person<T1,T2>::Person(T1 name, T2 age) { this->m_Name = name; this->m_Age = age; } void test() { Person<std::string, int> p("Tom", 99); p.showPerson(); } int main(void) { test(); return 0; }
类外实现需要将实现定义为函数模板,并且指明类型!
#include<iostream> #include<string> //通过全局函数来打印Person信息 //让编译器提前知道类外实现,而且还要在此基础上提前让它知道Person类! template<class T1, class T2> class Person; template<class T1, class T2> void printPerson_2(Person<T1, T2>p) { std::cout << "类外实现------姓名:" << p.m_Name << " 年龄:" << p.m_Age << std::endl; } template<class T1, class T2> class Person { public: Person(T1 name, T2 age) { this->m_Name = name; this->m_Age = age; } //全局函数类内实现 friend void printPerson_1(Person<T1,T2>p) { std::cout << "类内实现------姓名:" << p.m_Name << " 年龄:" << p.m_Age << std::endl; } //全局函数类外实现 friend void printPerson_2<>(Person<T1, T2>p);//需要多加一个"<>"空模板参数列表 指明这是一个类外实现! private: T1 m_Name; T2 m_Age; }; //类外的实现在下方会链接出错!这需要让编译器提前知道(因为成了模板) //template<class T1, class T2> //void printPerson_2(Person<T1, T2>p) //{ // std::cout << "类外实现------姓名:" << p.m_Name << " 年龄:" << p.m_Age << std::endl; //} void test01() { Person<std::string, int> p("Tom", 99); printPerson_1(p); } void test02() { Person<std::string, int> p("Jerry", 88); printPerson_2(p); } int main(void) { test01(); test02(); }
友元的类外实现还是不太容易的,需要让编译器提前知道,定义也要有变化(笔者写容器的迭代器用到类中类时,遇到过这个问题)