C++模板
C++提供了模板(template)编程的概念。所谓模板,实际上是建立一个通用函数或类,其类内部的类型和函数的形参类型不具体指定,用一个虚拟的类型来代表。这种通用的方式称为模板。模板是泛型编程的基础,泛型编程即以一种独立于任何特定类型的方式编写代码。
C++函数模板的使用
所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来代表。这个通用函数就称为函数模板。 凡是函数体相同的函数都可以用这个模板来代替,不必定义多个函数,只需在模板中定义一次即可。在调用函数时系统会根据实参的类型来取代模板中的虚拟类型,从而实现了不同函数的功能。
由以下三部分组成:
模板说明 + 函数定义 + 函数模板调用
template < 类型形式参数表 > 类型
函数名 ( 形式参数表 )
{
//语句序列
}
#include <iostream> using namespace std;
template <typename T> T Max(T a, T b){ return a>b ? a:b; } int main() { int x = 1; int y = 2; cout<<"max(1, 2) = "<<Max(x, y)<<endl; cout<<"max(1, 2) = "<<Max<int>(x,y)<<endl; float a = 2.0; float b = 3.0; cout<<"max(2.0, 3.0) = "<<Max(a, b)<<endl; return 0; }
|

函数模板和普通函数区别结论:
两者允许并存
函数模板不允许自动类型转化
普通函数能够进行自动类型转换
函数模板和普通函数在一起,调用规则:
编译器并不是把函数模板处理成能够处理任意类型的函数
编译器从函数模板通过具体类型产生不同的函数
类模板的使用
类模板与函数模板的定义和使用类似,有时,有两个或多个类,其功能是相同的,仅仅是 数据类型不同,我们可以通过如下面语句声明了一个类模板:
template <typenameType> classClassName { private: TypeDataMember; }
template<typename T> class A { public: A(T t){ this->t=t; } T& getT(){ return t; } public: T t; };
|
类模板用于实现类所需数据的类型参数化
类模板在表示支持多种数据结构显得特别重要,这些数据结构的表示和算法不受所 包含的元素类型的影响
简单样例:
#include<iostream> using namespace std;
template<typename T> class A { public: A(T t){ this->t=t; } T& getT(){ return t; } public: T t; };
void printA(A<int> &a){ cout<<a.getT()<<endl; }
int main(){ A<int> a(666);
cout<<a.getT()<<endl; printA(a);
return 0; }
|
继承中类模板的使用
子类从模板类继承的时候,需要让编译器知道父类的数据类型具体是什么
#include<iostream> using namespace std;
template<typename T> class A { public: A(T t){ this->t=t; } T& getT(){ return t; } public: T t; };
template<typename Tb> class B:public A<Tb>{ public: B(Tb b):A<Tb>(b){ this->b = b; } private: Tb b; };
void printA(A<int> &a){ cout<<a.getT()<<endl; }
int main(){ A<int> a(666); cout<<a.getT()<<endl;
B<int> b(888);
cout<<"b(888):"<<b.getT()<<endl;
printA(a); printA(b);
return 0; }
|
类模板函数的三种表达描述方式
对与第二点:所有的类模板函数写在类的外部,在一个cpp中
template<typename T> class A { public: A(T t); T& getT(); public: T t; };
template<typename T> A<T>::A(T t){ this->t=t; }
template<typename T> T& A<T>::getT(){ return this->t; }
|
在同一个cpp文件中把模板类的成员函数放到类的外部,需要注意以下几点
对于第三点:所有的类模板函数写在类的外部,在不同的.h和.cpp中
#ifndef SIMPLE_TEMPLATE_CLASS #define SIMPLE_TEMPLATE_CLASS
template<typename T> class A { public: A(T t); T& getT(); public: T t; };
#endif
#include"simpleTemplateClass.h" using namespace std;
template<typename T> A<T>::A(T t){ this->t=t; }
template<typename T> T& A<T>::getT(){ return this->t; }
#include "simpleTemplateClass.h" #include "simpleTemplateClass.cpp" #include <iostream> using namespace std;
void printA(A<int> &a){ cout<<a.getT()<<endl; }
int main(){ A<int> a(666);
cout<<a.getT()<<endl; printA(a);
return 0; }
|
注意:当类模板的声明(.h文件)和实现(.cpp或.hpp文件)完全分离,因为类模板的特殊实现, 我们应在使用类模板时使用#include包含实现部分的.cpp或.hpp文件。
特殊情况友元函数
#include<iostream> using namespace std;
template<typename T> class A; template<typename T> A<T> addA(const A<T>& a, const A<T>& b);
template<typename T> class A { public:
A();
A(T t); T& getT();
friend A<T> addA<T>(const A<T>& a, const A<T>& b);
void print(); public: T t; };
template<typename T> A<T>::A(){}
template<typename T> A<T>::A(T t){ this->t=t; }
template<typename T> T& A<T>::getT(){ return this->t; }
template<typename T> void A<T>::print(){ cout<<this->t<<endl; }
template<typename T> A<T> addA(const A<T> &a, const A<T> &b){ A<T> tmp; cout<<"call add A()..."<<endl; tmp.t=a.t+b.t; return tmp; }
int main(){ A<int> a(666),b(888); A<int> tmp1=addA<int>(a,b); tmp1.print();
return 0; }
|
模板类和静态成员
#include <iostream> #include <string>
template <typename T> class MyClass { private: static T staticValue; T value;
public: MyClass(T val) : value(val) { staticValue = val; }
static void printStaticValue() { std::cout << "Static Value: " << staticValue << std::endl; }
static void setStaticValue(const T& newVal) { staticValue = newVal; }
void printValue() const { std::cout << "Value: " << value << std::endl; } };
template <typename T> T MyClass<T>::staticValue = T();
int main() { MyClass<int> obj1(10); MyClass<int> obj2(20);
obj1.printStaticValue(); obj2.printStaticValue();
MyClass<int>::setStaticValue(100);
obj1.printStaticValue(); obj2.printStaticValue();
obj1.printValue(); obj2.printValue();
MyClass<std::string> obj3("Hello");
obj3.printStaticValue();
MyClass<std::string>::setStaticValue("World");
obj3.printStaticValue();
return 0; }
|
从类模板实例化的每个模板类有自己的类模板数据成员,该模板类的所有对象共享一个static数据成员
和非模板类的static数据成员一样,模板类的static数据成员也应该在文件范围定义和初始化
static 数据成员也可以使用虚拟类型参数T