c++学习笔记(15.类模板)(一)

2014-11-24 08:28:31 · 作者: · 浏览: 2

本节知识点:

1.类模板是函数模板的升级:

a. c++中可以将模板的思想应用于类,使得类可以不关注具体所操作的数据类型,而只关注类所需要实现的功能。 b. 函数模板是使一个函数体适合各种类型的数据,类模板是使一个类适合各种类型的数据(包括成员函数和成员变量,当使得成员函数满足各种类型的数据的时候,其实就是在使用函数模板,所以说类模板是函数模板的升级) ,函数模板是类模板中的一部分。 c.类模板常用于一些存储和组织数据元素的类中,如:数组类、链表类、stack类、queue类等

2.类模板的语法规则:

a. 类模板的作用就是提供一种特殊的类以相同的行为处理不同的类型 b.类模板的使用跟函数模板的使用一样,在定义类的前面声明template ,说明类中使用泛指类型T c.类模板的应用,当使用类模板定义对象时,要指明具体类型,如:test t1 即t1就是满足int类型的对象 示例代码,如下:
#include 
    
     

using namespace std;

template 
     
       class test { public: int a; T a1; T add(T b, T c) { return b + c; } T min(T b, T c); }; template 
      
        T test
       
        ::min(T b, T c) { return b - c; } int main() { test
        
          t1; cout << t1.add(4, 6) << endl; cout << t1.min(6, 4) << endl; return 0; } 
        
       
      
     
    

注意:声明的泛指类型T可用于声明成员变量和成员函数

3.类模板的深入理解:

a. 对于函数模板,编译器进行了两次编译,第一次是直接对函数模板进行编译,看函数模板是否存在语法错误。第二次是在指明类型,让函数模板创建出具体类型的函数,调用具体类型的函数的时候,对具体函数进行编译。最终程序中只存在具体类型的函数,不存在函数模板。 b. 类模板跟函数模板的处理方式是一样的,也是进行两次编译,第一次是对类模板进行编译,判断类模板是否存在语法错误。第二次是在类模板创建出具体类型的对象之后 test t1 ,当t1对象调用类模板中的成员函数的时候,调用那个成员函数就会产生那个类模板成员函数的具体类型的函数(这里是int类型的函数),没调用的类模板成员函数则不会产生可执行代码,调用的类模板成员函数才会产生具体类型的函数(具体类型是根据调用者的对象决定的),才会产生可执行代码。

4.函数模板与类模板的工程应用:

a. 一般在工程中,函数的实现和函数的调用是在不同的文件中的,类的实现和类的使用也是在不同的文件中的。但是对于函数模板和类模板,模板的实现和使用必须在同一个文件中。因为模板是要在使用的时候,进行二次编译的,如果不在同一个文件中,当使用模板的时候编译器进行二次编译就找不到模板了。会产生链接错误!所以函数模板和类模板不能像普通函数和普通类一样分开实现后,在使用时只包括头文件!必须要把使用和实现放在一起。在工程实践中,一般会把类模板的定义直接放在头文件中,此时使用的头文件不再是 .h文件了,是 .hpp文件。hpp文件,就是告诉程序员,其中存放的是模板的实现,其实在编译的时候,hpp文件中的内容会被包含到#include "test.hpp"指定的cpp文件中去,这里面之所以表面上分开存放在hpp文件和cpp文件中,是为了开发的时候,使得代码工程清晰明了,有层次感! \ 注意:第一,Operator :: add 中的 Operator 表示的是Operator是一个类模板 第二,在类模板中的成员函数中,凡是有类名(即Operator)表示类的时候(即不是表示构造与析构函数名的时候),都要在类名后面加上 如Operator ,来表示是一个类模板,不管是函数的返回值类型啊,表示所属类啊,还是函数的参数类型啊,都要注意这一点! 示例代码(报链接错误的): main.cpp:
#include 
    
     
#include "test.h"

using namespace std;

int main()
{
	test
     
       t1; cout << t1.add(4,6) << endl; return 0; }
     
    
test.cpp:
#include "test.h"

template 
    
     
T test
     
       :: add(T a, T b) { return a + b; } 
     
    
test.h:
#ifndef TEST_H_
#define TEST_H_
template 
    
     
class test
{
public:
	int a;
	T add(T a, T b);
};

#endif
    

示例代码(正确的):
main.cpp:
#include 
    
     
#include "test.hpp"

using namespace std;

int main()
{
	test
     
       t1; cout << t1.add(4,6) << endl; return 0; }
     
    
test.hpp:
#include "test.h"

template 
    
     
T test
     
       :: add(T a, T b) { return a + b; } 
     
    
test.h:
#ifndef TEST_H_
#define TEST_H_
template 
    
     
class test
{
public:
	int a;
	T add(T a, T b);
};

#endif
    

5.类模板的特化:

a.类模板是可以被特化的,用template<>声明一个类时,表示这是一个特化类! b. 类模板的特化与函数模板的特化是一样的,这种特化都是不需要进行二次编译的,所以说是编译器事先编译好的,当然这种特化不管是调用与否,都会被编译成为可执行代码的,这一点是与模板的本质区别!
c. 特化类模板的意义:当类模板在处理某种特定类型有缺陷时,可以通过类模板的特化来克服处理这种特定类型带来的不足。
d. 注意:编译器会优先选择特化类生成对象!! 示例代码:
#include 
    
     

using namespace std;

template 
     
       //test 类模板 class test { public: T a; T add(T b1, T b2) { return b1 + b2; } }; template <> class test
      
        //test类模板 的 int特化 { public: int add() { cout << "hello int" << endl; return 0; } }; int main() { test
       
         t; cout << t.add() << endl; test
        
          t1; cout << t1.add(2.1, 3.0) << endl; return 0; } 
        
       
      
     
    
注意:函数模板的特化与类模板的特化有一个最大的区别,就是函数模板与其特化的函数原型必须完全相同(即函数的名称,参数个数必须相同),而类模板与其特化的类仅仅类名相同就行了,类里面的内容可以完全不一样。

6.类模板的局部特化:

a.类模板可以定义多个类型参数,template b. 类模板可以被局部特化,即有些参数指明具体类型,有些参数依然保留模板特性。所以可想而知,局部特化的类模板,依然是模板,依然需要进行二次编译,所以如果没有调用该类模板中的成员函数,函数是不会被编译成为可执行代码的。这点是与类模板的全部特化是不一样的! 示例代码:
#include 
     
      

using namespace std;

template 
      
        class test { public: void fun() { cout << "T1 T2 " << endl; } }; template 
       
         class test
        
          { public: void fun() { cout << "T T " << endl; } }; template 
         
           class test
          
            { public: void fun() { cout << "T int" << endl; } }; template 
           
             class test
            
              { public: void fun() { cout << "T1* T2*" << endl; } }; int main() { test
             
               t1; t1.fun(); test
              
                t2; t2.fun(); test
               
                 t3; t3.fun(); test
                
                  t4; t4.fun(