模板是非常灵活的事物。是C++众多复杂思想中较为容易的一个,但是也是非常有用的。
注意:模板既可以在头文件中定义,也可以在你使用它们的C++源码文件中定义。定义它,又不能像正常函数和类那样定义。
假设你想在一个结构体包含一个对象数组:
struct{ object a[500]; }但是现在你又想要一个double数组:
struct{ double a[500]; }或者任何其它类型的数组。模板允许你使用通配符代替真实的类型。
template <typename T> struct vector { T a[500]; }模板完全是在编译时有用。也就是说,模板意味着更长的编译时间,但是不会影响你的应用程序的执行时间。因为当程序被编译时,模板完成实例化。
template<typename T> struct vector { T f(); }; struct Abstract_Base { virtual void func() = 0; }; struct Derived { virtual void func() {} }; int main() { vector<Derived> vector_of_deriveds; }经过编译器编译后的代码为:(注意:这不会真实发生,但是遵循通用思想)
struct vector<Derived> { Derived f(); }; struct Abstract_base .... and on like normal.对于你在模板对象中你实例化的特定类型。一个特定的类将会被创建,适应它。如果你使用没有vector<>对象,也就没有no vector<>类被创建。
int main() { vector<Abstract_Base> vector_of_abstract; }因为C++的规则,抽象基类(ABC)不能被创建。它有未定义的函数,且C++无法轻易地保证ABC不会调用它们。(一个指针能够隐藏ABC真正的身份)。 只要ABC遵循任何一个其它对象的规则,就可以作为一个类型名被使用。但是,这里却有一个问题。假设创建一个这样的类:
struct vector<Abstract_Base> { Abstract_Base a[500]; };这将会违反C++的规则,且会在编译时引发一个错误。因为抽象基类是不能创建对象的。
模板可以像正常类那样被派生:
template <typename T> class Base { virtual T* clone() const; }; template<typename T> class Derived : public Base<T> // 注意语法 { virtual T* clone() const; };这是合法的代码。T* clone()会在派生类Derived中被重写。 注意:有一些编译器,像gcc的某些版本(当然了,并不是现在的,主流的版本),如果不使用参数调用父类的基类,将会给出错误。只需要在前面加上this->指针就好了。
这个也是合法的代码。Object 不用和任何其它的Object<任何其它类型> 相同。
编译器会通过函数的第一个参数侦测到T是什么类型。它并不会提升T类型,除非你自己手动转换:
int main() { std::string* temp; temp = clone<std::string>("string-thang"); // this casts from a char* to a std::string return 0; }模板可以应用在元编程中。使用它,你能够不用遍历,创建大的,编译列表等等;所有的都不以牺牲运行效率为前提。(有时候,还会提升运行效率)。 这是一个编译时进行链接的链表例子:
template<typename F, typename L> struct cons { F first; L last; }; struct nil {}; //empty class Console { private: typedef //here's the magic cons < int, cons < double, cons < vector < int >, nil > > > list_of_types; list_of_types l_o_s; public: Console(); };重要的是,你可以在程序编译的时候处理你的对象列表。也可以使复杂的东西简单化。 当你在类中处理大量的对象时,你需要为每一个编写一个独一无二的名字,像OBJ_1, OBJ_2, … OBJ_31。这样,对于编程者来说是有意义的,但是修改它们的时候却是非常麻烦。
Console::Console() { parse(l_o_s); } typename <typename F, typename L> void parse(cons<F,L>& listing) { add_pointer(&listing.first); parse(listing.last); } void parse(nil&) {}模板也可以实现在编译时进行计算:
template <unsigned int x> struct factorial { static const unsigned int result = factorial<x-1>::result * x; }; template<> struct factorial<0> { static const unsigned int result = 1; }; int main () { return factorial<3>::result; // exactly the same as return 6; }真诚希望你能明白模板能做什么。因为当正确使用它的时候,确实可以节省很多时间。