C++中类模板的概念和意义
1,在 C++ 中是否能够将泛型的思想应用于类?
1,函数模板是将泛型编程的思想应用于函数,就有了函数模板;
2,可以,常用的 C++ 标准库就是 C++ 中的标准模板库,C++ 中的 STL 就是将泛型的思想应用于一系列的函数,就得到了函数模板,当然也有很多的类模板;
3,类模板就是将泛型思想应用于 C++ 中的类而得到的新概念;
2,类模板:
1,一些类主要用于存储和组织数据元素;
1,类模板就是为了数据结构而诞生的;
2,类中数据组织的方式和数据元素的 具体类型无关;
3,如:数组类、链表类、Stack 类、Queue 类等;
1,C++ 中将模板的思想应用于类,使得类的实现不关注数据元素的具体类型,而只关注类所需实现的功能;
3,C++ 中的类模板:
1,以相同的方式处理不同的类型;
2,在类声明前使用 template 进行标识;
3,< typename T > 用于说明类中使用的泛指类型 T;
1,代码示例:
1 template < typename T > 2 class Operator // class 表明将泛型编程应用于类 3 { 4 public: 5 T op(T a, T b) // T 在使用类模板定义具体对象的时候关心,其它时候不关心; 6 };
4,类模板的应用:
1,只能显示指定具体类型,无法自动推导;
2,使用具体类型 < Type > 定义对象;
1,代码示例:
1 Operator<int> op1; 2 Operator<string> op2; 3 int i = op1.op(1, 20); 4 string s = op2.op("D.T.", "Software");
4,类模板:
1,声明的泛指类型 T 可以出现在类模板的任意地方;
2,编译器对类模板的处理方式和函数模板相同;
1,从类模板通过具体类型产生不同的类;
1,编译器将类模板当做一个模子,这个模子可以产生许多实实在在的类;
2,在声明的地方对类模板代码本身进行编译;
3,在使用的地方对参数替换后的代码进行编译;
5,类模板初探编程实验:
1 #include <iostream> 2 #include <string> 3 4 using namespace std; 5 6 template < typename T > 7 class Operator // 要是用这个类模板有一个前提条件,即当前的 Operator 类模板要操作的数据类型必须支持 +、-、*、/ 这四个运算符,这四个运算符如果要运用于自己定义的数据类型类,要重载这四个运算符;第一次编译是对类模板本身的语法进行编译; 8 { 9 public: 10 T add(T a, T b) 11 { 12 return a + b; 13 } 14 15 T minus(T a, T b) 16 { 17 return a - b; 18 } 19 20 T multiply(T a, T b) 21 { 22 return a * b; 23 } 24 25 T divide(T a, T b) 26 { 27 return a / b; 28 } 29 }; 30 31 string operator-(string& l, string& r) // 全局函数方式重载 - 操作符,编译通过;先类内部、再全局 32 { 33 return "Minus"; // 仅仅为了说明问题; 34 } 35 36 int main() 37 { 38 Operator<int> op1; 39 40 cout << op1.add(1, 2) << endl; // 3; 41 42 Operator<string> op2; // 第二次使用类模板时进行编译,但是并不是对所有模板中的函数进行了第二次编译,是分步编译的,首先编译的是构造函数,此时用的是默认的,没有问题,这里编译通过; 43 44 cout << op2.add("D.T.", "Software") << endl; // D.T.Software;这里编译器针对 add() 函数进行第二次编译; 45 cout << op2.minus("D.T", "Software") << endl; // 未有定义全局的重载 - 操作符的函数时,字符串相减没有定义,报错;这里报错展示出来是为了证明类模板编译也是经过了两次编译;这里编译器针对 minus() 函数进行第二次编译;定义全局的重载 - 操作符函数后,打印 Minus ; 46 47 return 0; 48 }
1,编译器对类模板第一次编译针对类模板本身代码进行编译;
2,第二次编译是使用类模板时针对每个成员函数独立编译;
6,类模板的工程应用:
1,类模板必须在头文件中定义;
2,类模板不能分开实现在不同的文件中;
3,类模板外部定义的成员函数需要加上模板 <> 声明;
1,将类模板的成员函数实现放到类模板的外部实现;
2,以上三条规则不是 C++ 和编译器的一部分,只是工程应用里习惯这样做,这样做后,代码可维护性、扩展性都会变好,因此建议遵守这三条规则;
7,模板类的工程应用编程实验:
1,头文件(名字和类名一样) Operator.h 中的内容:
1 #ifndef _OPERATOR_H_ // 防止被包含两次; 2 #define _OPERATOR_H_ 3 4 template < typename T > 5 class Operator 6 { 7 public: 8 T add(T a, T b); 9 T minus(T a, T b); 10 T multiply(T a, T b); 11 T divide(T a, T b); 12 }; 13 14 template < typename T > // 加上类模板; 15 T Operator<T>::add(T a, T b) // add() 是 Operator 类模板的; 16 { 17 return a + b; 18 } 19 20 template < typename T > 21 T Operator<T>::minus(T a, T b) 22 { 23 return a - b; 24 } 25 26 template < typename T > 27 T Operator<T>::multiply(T a, T b) 28 { 29 return a * b; 30 } 31 32 template < typename T > 33 T Operator<T>::divide(T a, T b) 34 { 35 return a / b; 36 } 37 38 #endif
2,头文件的应用;
1 #include <iostream> 2 #include <string> 3 #include "Operator.h" 4 5 using namespace std; 6 7 int main() 8 { 9 Operator<int> op1; 10 11 cout << op1.add(1, 2) << endl; // 3; 12 cout << op1.multiply(4, 5) << endl; // 20; 13 cout << op1.minus(5, 6) << endl; // -1; 14 cout << op1.divide(10, 5) << endl; // 2; 15 16 return 0; 17 }
1,三条规则不是硬性要求但是却可以带来很大好处;
8,小结:
1,泛型编程的思想可以应用于类;
2,类模板以相同的方式处理不同类型的数据;
3,类模板非常适用于编写数据结构相关的代码;
4,类模板在使用时只能显示指定类型;