类模板
1.7 类模板
1.7.1 类模板基本概念
类模板和函数模板的定义和使用类似,我们已经进行了介绍。有时,有两个或多个类,其功能是相同的,仅仅是数据类型不同。
l 类模板用于实现类所需数据的类型参数化
template<class NameType, class AgeType> class Person { public: Person(NameType name, AgeType age) { this->mName = name; this->mAge = age; } void showPerson() { cout << "name: " << this->mName << " age: " << this->mAge << endl; } public: NameType mName; AgeType mAge; }; void test01() { //Person P1("德玛西亚",18); // 类模板不能进行类型自动推导 Person<string, int>P1("德玛西亚", 18); P1.showPerson(); }
1.7.2 类模板做函数参数
#include "stdafx.h" #include <iostream> using namespace std; #include <string> template <class NameType,class AgeType> class Person { public: Person(NameType name, AgeType age) { this->m_Name = name; this->m_Age = age; } void PrintPerson() { cout << "Name:" << this->m_Name << " Age:" << this->m_Age << endl; } NameType m_Name; AgeType m_Age; }; void DoBussiness(Person<string, int>& p) { p.m_Age += 20; p.m_Name += "_VIP"; p.PrintPerson(); } //2.参数模板化 template<class T1,class T2> void doWork(Person<T1, T2>&p) { cout << typeid(T1).name() << endl; cout << typeid(T2).name() << endl; p.PrintPerson(); } //3.整体类型化 template<class T> void doWork3(T& p) { cout << typeid(T).name() << endl; p.PrintPerson(); } int main() { Person<string,int> p("sunwukong", 100); //p.PrintPerson(); DoBussiness(p); doWork(p); doWork3(p); return 0; }
1.7.3 类模板派生普通类
//类模板 template<class T> class MyClass{ public: MyClass(T property){ this->mProperty = property; } public: T mProperty; }; //子类实例化的时候需要具体化的父类,子类需要知道父类的具体类型是什么样的 //这样c++编译器才能知道给子类分配多少内存 //普通派生类 class SubClass : public MyClass<int>{ public: SubClass(int b) : MyClass<int>(20){ this->mB = b; } public: int mB; };
#include <iostream> using namespace std; #include <string> template<class T> class Base { public: T m_A; }; class Child :public Base<int> { }; template <class T1,class T2> class Child2 :public Base<T1> { public: T1 m_B; }; int main() { Child2<int, double> c2; return 0; }
1.7.5 类模板类内实现
template<class NameType, class AgeType> class Person { public: Person(NameType name, AgeType age) { this->mName = name; this->mAge = age; } void showPerson() { cout << "name: " << this->mName << " age: " << this->mAge << endl; } public: NameType mName; AgeType mAge; }; void test01() { //Person P1("德玛西亚",18); // 类模板不能进行类型自动推导 Person<string, int>P1("德玛西亚", 18); P1.showPerson(); }
1.7.6 类模板类外实现
class Person{ public: Person(T1 name, T2 age); void showPerson(); public: T1 mName; T2 mAge; }; //类外实现 template<class T1, class T2> Person<T1, T2>::Person(T1 name, T2 age){ this->mName = name; this->mAge = age; } template<class T1, class T2> void Person<T1, T2>::showPerson(){ cout << "Name:" << this->mName << " Age:" << this->mAge << endl; } void test() { Person<string, int> p("Obama", 20); p.showPerson(); } int main(){ test(); system("pause"); return EXIT_SUCCESS; }
1.7.7 类模板头文件和源文件分离问题
Person.hpp
#pragma once #include <iostream> using namespace std; template<class T1,class T2> class Person { public: Person(T1 t1, T2 t2); ~Person(); void PrintInfo() { cout << "------------void PrintInfo()--------------" << endl; cout << "m_a: " << m_a << " "<< typeid(T1).name() << endl; cout << "m_b: " << m_b << " " <<typeid(T2).name() << endl; cout << "------------------------------------------" << endl; } void showInfo(); T1 m_a; T2 m_b; }; template<class T1,class T2,class T3> class xiaoming :public Person<T1, T2> { public: xiaoming(T1 a, T2 b, T3 c); ~xiaoming(); void showInfo(); T3 m_c; }; template<class T1, class T2> Person<T1, T2>::Person(T1 t1, T2 t2) :m_a(t1) , m_b(t2) { } template<class T1, class T2> Person<T1, T2>::~Person() { } template<class T1, class T2> void Person<T1, T2>::showInfo() { cout << "---------------void Person<T1,T2>::showInfo()---------------" << endl; cout << "m_a: " << m_a << " " << "m_b: " << m_b << " " << endl; cout << "--------------------------------------------------------------" << endl; } template<class T1, class T2, class T3> xiaoming<T1, T2, T3>::xiaoming(T1 a, T2 b, T3 c) :Person(a, b) , m_c(c) { } template<class T1, class T2, class T3> xiaoming<T1, T2, T3>::~xiaoming() { } template<class T1, class T2, class T3> void xiaoming<T1, T2, T3>::showInfo() { cout << "---------void xiaoming<T1, T2, T3>::showInfo()----------" << endl; cout << "m_a: " << m_a << " " << typeid(T1).name() << endl; cout << "m_b: " << m_b << " " << typeid(T2).name() << endl; cout << "m_c: " << m_c << " " << typeid(T3).name() << endl; cout << "--------------------------------------------------------" << endl; }
调用
#include "stdafx.h" #include <iostream> using namespace std; #include <string> //#include "Person.h" #include "Person.hpp" int main() { //Child2<int, double> c2; Person<int, string> p1(10,"test p1"); p1.showInfo(); p1.PrintInfo(); xiaoming<int, string, int> p2(10, "xiaoming", 1000); p2.showInfo(); p2.PrintInfo(); return 0; }
结论: 案例代码在qt编译器顺利通过编译并执行,但是在Linux和vs编辑器下如果只包含头文件,那么会报错链接错误,需要包含cpp文件,但是如果类模板中有友元类,那么编译失败!
解决方案: 类模板的声明和实现放到一个文件中,我们把这个文件命名为.hpp(这个是个约定的规则,并不是标准,必须这么写).
原因:
l 类模板需要二次编译,在出现模板的地方编译一次,在调用模板的地方再次编译。
l C++编译规则为独立编译。
1.7.8 模板类碰到友元函数
// Template02.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include <iostream> using namespace std; #include <string> //2.2 外部实现1 前置声明 template<class T1, class T2> class Person; //2.3 外部实现1 外部声明友元 template<class T1, class T2> void PrintPerson2(Person<T1, T2>& p); template<class T1,class T2> class Person { //3 外部实现2 template<class U1, class U2> friend void PrintPerson3(Person<U1, U2>& p); //2.1外部实现1 friend void PrintPerson2<>(Person<T1, T2>& p); //1.内部实现 friend void PrintPerson(Person<T1, T2>& p) { cout << "Name:" << p.m_Name << " Age:" << p.m_Age << endl;; } public: Person(T1 name, T2 age) { this->m_Name = name; this->m_Age = age; } void showPerson() { cout << "Name:" << this->m_Name << " Age:" << this->m_Age << endl; } private: T1 m_Name; T2 m_Age; }; template<class T1,class T2> void PrintPerson2(Person<T1, T2>& p) { cout << "Name:" << p.m_Name << " Age:" << p.m_Age << endl; } template<class U1, class U2> void PrintPerson3(Person<U1, U2>& p) { cout << "Name:" << p.m_Name << " Age:" << p.m_Age << endl; } int main() { Person<string, int> p("sunwukong", 20); //p1.showPerson(); //PrintPerson2(p); PrintPerson3(p); return 0; }