c++类模板深度剖析
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c++类模板深度剖析相关的知识,希望对你有一定的参考价值。
1、类模板的泛指类型可以定义多个 template <typename T1, typename T2> class Test { public: void add(T1 a, T2, b); }; 使用时: Test<int, float> t1; //T1的泛指类型就是int, T2的泛指类型就是float。 2、类模板的特化类型 (1)意思就是如果定义了一个类模板,这个类模板的参数有多个,但是如果当使用这个类模板的时候,我们传递参数时,参数的类型是一样的话,编译器就会将类模板特化成一个参数的类模板。 (2)类模板的特化分为:部分特化,和完全特化。 部分特化:用特定规则约束类型参数,部分类型参数必须显示指定,根据类型参数分开实现类模板 如: template 特化后 template < typename T1, typname T2 > < typename T > class Test class Test <T, T> //部分特化的约束条件 { { }; }; 当类型参数不同的时候,会选择用左边的那个类模板,当类型参数相同的时候。class Test< T, T>就是约束条件 完全特化:完全显示指定类型参数 如: template 特化后 template < typename T1, typname T2 > < > //完全特化时,不需要声明泛指类型 class Test class Test <int, int> //这个就是完全特化 { { }; }; 当使用类模板的时候,并且指定了所有的类型参数全都是一样的,比如int的时候,编译器就会将左边的类模板特化成右边的类模板,此时该类模板中就没有泛指类型了。 当类型参数不同的时候,就会使用左边的类模板。 (3)根据实验的例子,类模板的特化就是程序中有了一个左边的类模板的时候(这个类模板的有两个泛指类型),但是同时程序中我们又定义了一个同名的类模板,但是这个类模板的两个泛指类型都是一样的。这个时候,当我们在程序中使用这个类模板的时候,如果参数类型是不一样的,编译器就会使用左边的那个,如果参数类型是一样的时候,编译器就会使用右面的那个。编译器会认为右边的那个类模板,是左边的类模板的一种特化,编译器不会认为左边的类模板是一个新的类模板,只是一个左边类模板的一个特化,所以编译能够通过。 总结:将一个类模板,根据不同的类型参数情况进行分开实现这个类模板,其实就是一个类模板的特化过程。 例: #include <iostream> using namespace std; template < typename T1, typename T2 > class Test { public: void add(T1 a, T2 b) { cout << "void add(T1 a, T2 b)" << endl; cout << a + b << endl; } }; /*****************************************************部分特化*************************************************/ template < typename T> class Test < T, T > //这个地方加上了约束条件,虽然这个类模板跟上面的那个类模板同名,编译器不会认为这个类模板是一个新的类模板,而是上面类模板的一个特化形式, { //当我们使用Test类模板的时候,如果指定的参数类型不同的话,编译器就会使用上面的那个类模板实现,如果指定参数类型相同的话,编译器就会使用这个类模板的实现 public: void add(T a, T b) { cout << "void add(T a, T b)" << endl; cout << a + b << endl; } void print(void) //即使多出来了个print成员函数,编译也是通过的,所以是支持这种特化方式的 { cout << "class Test < T, T > " << endl; } }; /******************************************************完全特化**********************************************************/ template < > //进行类模板的完全特化时,不用进行泛指类型的声明 class Test <void *, void *> //当使用Test类模板时,参数类型都为void *时,就会使用这个实现。 { public: void add(void * a, void * b) { cout << "void add(void * a, void * b)" << endl; cout << "Error run not to add because type is void *..." << endl; } }; /*****************************************将Test类模板特化出一个两个参数分别是指针的情况**********************************************/ template < typename T1, typename T2> class Test < T1 *, T2 *> { public: void add(T1 *a, T2 *b) { cout << "void add(T1 *a, T2 *b)" << endl; cout << *a + *b << endl; } }; int main(void) { int a = 1; double b = 1.0; Test<int, float> t1; //使用的就是没有特化的Test类模板 Test<long, long> t2; //使用的就是特化后的Test类模板 Test<void *, void *> t3; Test<int *, double *> t4; t1.add(2, 2.5); t2.add(10, 10); t2.print(); t3.add(&a, &b); t4.add(&a, &b); return 0; } 3、继续理解类模板的特化 (1)类模板的特化的就是根据需要,将一个类模板进行分开来实现。特化只是模板的分开实现,本质上还是同一个类模板。特化类模板的使用方式是统一的,就是必须显示的指定每一个类型参数。 (2)问题:类模板特化与重定义有区别吗? 答:有区别,重定义和特化不同。在本质上,如果将一个类模板进行重定义,那么要么就是实现了一个新的类,要么就是最后会出现两个类模板。本质上不同。使用的时候不能进行统一使用, 在使用时我们要考虑选择哪个。 特化的本质是,只实现同一个类模板,只不过这个类模板是分开来实现的,这就是本质上的不同。在使用时是用统一的方式进行使用类模板和特化类,因为本质上都是实现了一个类模板,使用时 编译器会根据不同的参数类型来选择去使用那个类模板还是特化类。所以类模板的特化就是将一个类模板进行分开来实现,这句话是非常重要的。 (3)问题:函数模板可以特化吗? 答:函数模板只支持类型参数的完全特化,不支持部分特化,也就是在函数名的后面显示的指定出具体的参数类型。 如:函数模板的完全特化 template < typename T > bool Equal(T a, T b) //函数模板的定义 { return a == b; } template < > bool Equal<void *>(void *, void *) //函数模板的完全特化 { return a == b; } (4)工程中的建议:当需要重载函数模板的时候,我们要优先考虑使用模板特化的方式去分开实现一个函数模板,而是不用重载函数模板的方式去新的实现了一个函数,当模板特化无法满足要 求的时候,在使用函数重载。 工程中使用模板特化来代替类(函数)重定义。 例:类模板的部分特化、完全特化,函数模板的完全特化。优先考虑使用特化的方式当需要将模板进行重定义添加功能时。 #include <iostream> #include <string> using namespace std; /* * 特化的方式实现一个类模板,本质就是分开实现类模板 * */ template <typename T1, typename T2> class Why { public: void print(T1 a, T2 b) { cout << "void print(T1 a, T2 b)" << endl; cout << a << " " << b << endl; } }; template <typename T> class Why<T, T> //为类模板的部分特化 { public: void print(T a, T b) { cout << "void print(T a, T b)" << endl; cout << a << " " << b << endl; } }; template < > class Why<int, int> //为类模板的完全特化 { public: void print(int a, int b) { cout << "void print(int a, int b)" << endl; cout << a << " " << b << endl; } }; /* * 函数模板的特化只支持完全特化 * 实现一个函数模板,并且完全特化,也就是分开实现一个函数模板,这样叫做特化。 */ template <typename T> bool Equal(T a, T b) { return a == b; } template < > //函数模板的完全特化,之所以要特化这个函数模板是因为,浮点数的比较不单纯的只用==来比较。 bool Equal<double>(double a, double b) { const double delta = 0.00000000001; double r = a - b; cout << "bool Equal<double>(double a, double b)" << endl; return ((-delta < r) && (r < delta)); } /* * 重载Equal函数的方式来达到比较浮点数的方法,但这种方式是不优先考虑的,因为这种方式,在使用的时候要考虑如何选择,要优先考虑使用特化的方式。 * 能使用特化的方式时,就不考虑使用这种函数重载的方式,不论对于类模板还是函数模板都是这样的,优先考虑使用特化的方式来分开实现,因为这样都是为了实现一个类模板或函数模板。 */ bool Equal(double a, double b) { const double delta = 0.00000000001; double r = a - b; cout << "bool Equal(double a, double b)" << endl; return ((-delta < r) && (r < delta)); } int main(void) { double a = 0.0, b = 0.0; Why<int, double> w1; Why<string, string> w2; Why<int, int>w3; w2.print("why", "fangqingqing"); w1.print(1, 2.2); w3.print(100,100); cout << "Please input two double number..." << endl; cin >> a >> b; cout << Equal<double>(a, b) << endl; cin >> a >> b; cout << Equal(a, b) << endl; return 0; }
以上是关于c++类模板深度剖析的主要内容,如果未能解决你的问题,请参考以下文章