【C/C++】 类模板与模板类详解|函数指针\指针函数|函数模板和类模板|普通参数模板、类参数模板...

目录

类模板与模板类详解

简洁

详细

类模板的使用

函数指针\指针函数\模板类\类模板

模板函数与函数模板


类模板与模板类详解

简洁

类模板:模板

模板类:实例

模板类是类模板实例化后的一个产物,说个具体点的例子吧,我们把类模板比作是一个做饼干的模子,而模板类就是用这个模子做出来的饼干,至于这个饼干是什么味道的就要看你自己在实例化时用的是什么材料了,你可以做巧克力饼干,也可以做牛奶饼干,这些饼干出了材料不一样外,其它的东西都是一样的了。

详细

template<typename T> 和 template<class T>等价

在C++的Template中很多地方都用到了typename与class这两个关键字,有时候这两者可以替换,那么这两个关键字是否完全一样呢?

  事实上class用于定义类,在模板引入c++后,最初定义模板的方法为:template<class T>,这里class关键字表明T是一个类型,后来为了避免class在这两个地方的使用可能给人带来混淆,所以引入了typename这个关键字,它的作用同class一样表明后面的符号为一个类型,这样在定义模板的时候可以使用下面的方式了:

  template<typename T>,在模板定义语法中关键字class与typename的作用完全一样

区分类模板与模板类的概念

  一个类模板(类生成类)允许用户为类定义个一种模式,使得类中的某些数据成员、默认成员函数的参数,某些成员函数的返回值,能够取任意类型(包括系统预定义的和用户自定义的)。

  如果一个类中的数据成员的数据类型不能确定,或者是某个成员函数的参数或返回值的类型不能确定,就必须将此类声明为模板,它的存在不是代表一个具体的、实际的类,而是代表一类类。

类模板定义

定义一个类模板,一般有两方面的内容:

A首先要定义一个类,其格式为:

template<class T>
class test
{

....

}

test为类名,在类定义体中,如果采用通用数据类型的成员,函数参数的前面需加上T,其中通用类型T可以作为普通成员变量的类型。还可以作为成员函数的参数和返回类型等。

例如:

template<class T>
class Test
{
private:
    T n;
    const T i;
public:
    Test():i(0) {}
    Test(T k);
    ~Test(){}

    void print();
    T operator+(T x);
};

如果在类外定义成员函数,若此成员函数中有模板参数存在,则除了需要和一般类的类外定义成员函数一样的定义外,还需要在函数外进行模板声明
例如:

template<class T>
void Test<T>::print()
 {
    std::cout<<"n="<<n<<std::endl;
    std::cout<<"i="<<i<<std::endl;
}
template<class T>
Test<T>::Test(T k):i(k){ n=k;}

template<class T>
T Test<T>::operator+(T x){
    return n + x;
}

类模板的使用

关于类模板的使用:类模板的使用实际上是将类模板实例化成一个具体的类,它的格式为:类名<实际的类型>

原文:C++ 类模板与模板类详解 - evilsnake - 博客园

函数指针\指针函数\模板类\类模板

模板函数与函数模板

1.函数指针——指针函数 

函数指针的重点是指针。表示的是一个指针,它指向的是一个函数,例子: 
int   (*pf)(); 
指针函数的重点是函数。表示的是一个函数,它的返回值是指针。例子: 
int*   fun(); 2.数组指针——指针数组 
数组指针的重点是指针。表示的是一个指针,它指向的是一个数组,例子: 
int   (*pa)[8]; 
指针数组的重点是数组。表示的是一个数组,它包含的元素是指针。例子; 
int*   ap[8]; 3.类模板——模板类(class   template——template  class) 
类模板的重点是模板。表示的是一个模板,专门用于产生类的模子。例子: 

template   <typename T> 
class   Vector 
{ 
          … 
};


使用这个Vector模板就可以产生很多的class(类),Vector <int> 、Vector <char> 、Vector <   Vector <int>   > 、Vector <Shape*> ……。
模板类的重点是类。表示的是由一个模板生成而来的类。

例子: 
上面的Vector <int> 、Vector <char> 、……全是模板类。 
这两个词很容易混淆,我看到很多文章都将其用错,甚至一些英文文章也是这样。将他们区分开是很重要的,你也就可以理解为什么在定义模板的头文件.h时,模板的成员函数实现也必须写在头文件.h中,而不能像普通的类(class)那样,class的声明(declaration)写在.h文件中,class的定义(definition)写在.cpp文件中。请参照Marshall   Cline的《C++   FAQ   Lite》中的[34]   Container   classes   and   templates中的[34.12]   Why   can 't   I  separate   the   definition   of   my  templates   class   from   it 's   declaration   and   put   it   inside   a  .cpp   file?  URL地址是http://www.parashift.com/c++-faq-lite/containers-and-templates.html#faq-34.12
我将几句关键的段落摘录如下,英文很好理解: 

In order for the compiler to generate the code, it must see both the template   definition  (not just declaration) and the specific  types/whatever used to "fill in "   the template.  For example, if you're trying to use a Foo <int> , the compiler must see   both the Foo template and the fact that you're trying to make a specific Foo <int> .  
Suppose you have a template Foo defined like this:   

  template <class T> 
  class  Foo { 
  public: 
     Foo(); 
      void someMethod(T  x); 
  private: 
      T  x; 
  };   

Along  with similar definitions for the member functions:   

  template <class   T> 
  Foo <T> ::Foo() 
  { 
     ... 
  } 
  
  template <class T> 
  void Foo <T> ::someMethod(T  x) 
  { 
     ... 
  }   

Now suppose you have some code in file  Bar.cpp  that  uses  Foo <int> :  

  //Bar.cpp 
  void  blah_blah_blah() 
  { 
     ... 
      Foo <int>  f; 
     f.someMethod(5); 
     ... 
  }   

Clearly somebody somewhere is going to have to use the "pattern " for the constructor   definition and for the someMethod() definition and instantiate those  when T is   actually  int. But if you had put the definition of the constructor and someMethod()   into file Foo.cpp, the compiler would see  the template code  when it compiled   Foo.cpp and  it  would see  Foo <int> when it  compiled  Bar.cpp, but there would   never be a  time when it saw both the template code and  Foo <int> .So by  rule  above,   it could never generate the code for Foo <int>::someMethod().

关于一个缺省模板参数的例子: 

template   <typename   T   =  int> 
class   Array 
{ 
          … 
};


第一次我定义这个模板并使用它的时候,是这样用的: 


Array   books;//我认为有缺省模板参数,这就相当于Array <int>  books 
上面的用法是错误的,编译不会通过,原因是Array不是一个类。正确的用法是Array <>  books; 
这里Array <> 就是一个用于缺省模板参数的类模板所生成的一个具体类。 4.函数模板——模板函数(function  template——template  function) 
函数模板的重点是模板。表示的是一个模板,专门用来生产函数。例子: 

template   <typename   T> 
void   fun(T  a) 
{ 
         … 
}

在运用的时候,可以显式(explicitly)生产模板函数,fun <int> 、fun <double> 、fun <Shape*> ……。 
也可以在使用的过程中由编译器进行模板参数推导,帮你隐式(implicitly)生成。 
fun(6);//隐式生成fun <int> 
fun(8.9);//隐式生成fun <double> 
fun(‘a’);//   隐式生成fun <char> 
Shape*   ps   =   new  Cirlcle; 
fun(ps);//隐式生成fun <Shape*> 
模板函数的重点是函数。表示的是由一个模板生成而来的函数。例子: 
上面显式(explicitly)或者隐式(implicitly)生成的fun <int> 、fun <Shape*> ……都是模板函数。 
关于模板本身,是一个非常庞大的主题,要把它讲清楚,需要的不是一篇文章,而是一本书,幸运的是,这本书已经有了:David   Vandevoorde,   Nicolai   M.   Josuttis写的《C++   Templates:   The   Complete  Guide》。可惜在大陆买不到纸版,不过有一个电子版在网上流传。
模板本身的使用是很受限制的,一般来说,它们就只是一个产生类和函数的模子。除此之外,运用的领域非常少了,所以不可能有什么模板指针存在的,即指向模板的指针,这是因为在C++中,模板就是一个代码的代码生产工具,在最终的代码中,根本就没有模板本身存在,只有模板具现出来的具体类和具体函数的代码存在。
但是类模板(class   template)还可以作为模板的模板参数(template   template   parameter)使用,在Andrei   Alexandrescu的《Modern   C++   Design》中的基于策略的设计(Policy   based   Design)中大量的用到。

template <   typename   T,   template <typename   U>   class  Y> 
class   Foo 
{ 
          … 
};

原文:模板函数与函数模板_fckkfc的博客-CSDN博客_模板函数和函数模板

类模板注意

注意:1)类模板不能嵌套(局部类模板)。

2)类模板中的静态成员仅属于实例化后的类(模板类),不同实例之间不存在共享。

类模板和函数模板

 模板提供了代码复用。在使用模板时首先要实例化,即生成一个具体的函数或类。函数模板的实例化是隐式实现的,即由编译系统根据对具体模板函数(实例化后的函数)的调用来进行相应的实例化,而类模板的实例化是显式进行的,在创建对象时由程序指定。

如果未使用到一个模板的某个实例,则编译系统不会生成相应实例的代码。

   在C++中,由于模块是分别编译的,如果在模块A中要使用模块B中定义的一个模板的某个实例,而在模块B中未使用这个实例,则模块A无法使用这个实例,除非在模块A中也定义了相应的模板。因此模板是基于源代码复用,而不是目标代码复用。

例:
// file1.h

template <class T>
class S
{
    T a;
public:
    void f();
};

// file1.cpp
#include "file1.h"
template <class T>
void S<T>::f()
{
    …
}

template <class T>
T max(T x, T y)
{
    return x > y ? x : y;
}

void main()
{
    int a, b;
    float m, n;
    max(a, b);
    max(m, n);
    S<int> x;
    x.f();
}

// file2.cpp
#include "file1.h"
extern double max(double, double);
void sub()
{
    max(1.1, 2.2); //Error,no appropriate instance
    S<float> x;
    x.f(); //Error, corresponding instance has no appropriate implementation
}

C++的函数模板和类模板|普通参数模板、类参数模板

2012-09-06 11:30:36

非类型(普通)参数模板

template <class T, int size,int size2 >
void f(char a) 
{
    
    char temp[size];
    char temp[size2];
    ......
}

void main()
{
    
    f<10,10>(1);
}

类型参数模板

简介:

//类声明
template<class T1, class T2> 
class VarToVar 
{
private :
     T1 m_source_vars_list;
     T2 m_dest_vars_list;
public:
    int Add(T1 source_node, T2 dest_node);
    VarToVar();
    virtual ~VarToVar();

};

详细:

理解这个 typedef double Type; 有助于理解模板, Type就代表了double,Type data  相当于 double data。

1、函数模板

函数模板的用途:

类属函数指一个函数对不同类型的数据完成相同的操作。

1、宏实现

#define max(a,b) ((a)>(b)?(a):(b))

不足之处:只能实现简单的功能,并且存在不作类型检查以及重复计算等问题。

2、函数重载

int max(int,int);
double max(double,double);
A max(A,A);

不足之处:需要定义的重载函数太多,如果定义不全会有问题。

如:

cout << max(‘3’,’5’); 将输出53而非‘5’。

3、指针实现

例:编写一个排序(sort)函数,使其能对各种数据进行排序(整型数序列、浮点数序列以及某个类的对象序列等)。

void sort(void *base, //需排序的数据首地址
          unsigned int count, //数据元素的个数
          unsigned int element_size, //数据元素的大小
          int (*cmp)(void *, void *) //比较两个数据元素
          //大小的函数指针
         )
{
    //取第i个元素
    (char *)base + i *element_size
    //比较第i个和第j个元素的大小
    (*cmp)((char *)base + i * element_size,
           (char *)base + j * element_size
          )
    //交换第i个和第j个元素
    char *p1 = (char *)base + i * element_size,
          *p2 = (char *)base + j * element_size;
    for (k = 0; k < element_size; k++)
    {
        char temp = p1[k];
        p1[k] = p2[k];
        p2[k] = temp;
    }
}

int int_compare(void *p1, void *p2)
{
    if (*(int *)p1 < * (int *)p2)
        return –1;
    else if (*(int *)p1 > *(int *)p2)
        return 1;
    else
        return 0;
}

int double_compare(void *p1, void *p2)
{
    if (*(double *)p1 < * (double *)p2)
        return –1;
    182
    else if (*(double *)p1 > *(double *)p2)
        return 1;
    else
        return 0;
}

int A_compare(void *p1, void *p2)
{
    if (*(A *)p1 < * (A *)p2) //类A需重载操作符:<
        return –1;
    else if (*(A *)p1 > *(A *)p2) //类A需重载操作符:>
        return 1;
    else
        return 0;
}

…
int a[100];
sort(a, 100, sizeof(int), int_compare);
double b[200];
sort(b, 200, sizeof(double), double_compare);
A c[300];
sort(c, 300, sizeof(A), A_compare);

不足之处:需要定义额外的参数,并且有大量的指针运算,使得实现起来麻烦、可读性差。

例:上述的排序用函数模板来实现。

template <class Type>

Type min( Type a, Type b ) ?

{

    return a < b ? a : b;

}

 Type统包了:int、float、double、string、char 等等类型,具体是哪一类,看实际引用,这就不必为每一个类型的数据都写一个函数了。

template <class T> //定义一个通用的参数T ,这个T指代哪种类型,视实例化为哪种类型

void sort(T elements[], unsigned int count)
{
    //取第i个元素
    elements [i]
    //比较第i个和第j个元素的大小
    elements [i] < elements [j]
    //交换第i个和第j个元素
    T temp = elements [i];
    elements [i] = elements [j];
    elements [j] = temp;
}
......
int a[100];
sort(a, 100);
double b[200];
sort(b, 200);
A c[300]; //类A中需重载操作符:<和=,给出拷贝构造函数
sort(c, 300);

函数模板定义了一类重载的函数,使用函数模板所定义的函数(模板函数)时,编译系统会自动把函数模板实例化。

模板的参数可以有多个,用逗号分隔它们,如:

template <class T1, class T2>  //T1\T2 代表::int、float、double、string、char 等等类型
void f(T1 a, T2 b)
{ ......
}

模板也可以带普通参数(非类型参数<非代表类型的参数>因为已经具体指明了参数类型)),它们须放在类型参数的后面,调用时需显式实例化,如:

template <class T, int size>
void f(T a) 
{
    
    T temp[size];
    ......
}

void main()
{
    
    f<int, 10>(1);
}

有时,需要把函数模板与函数重载结合起来用,例如:

template <class T>
T max(T a, T b)
{
    return a > b ? a : b;
}
…
int x, y, z;
double l, m, n;
z = max(x, y);
l = max(m, n);

问题:max(x,m)如何处理?

定义一个max的重载函数:

double max(int a, double b)
{
    return a > b ? a : b;
}

VC template模板的使用   类模板

//类声明
template<class T1, class T2> 
class VarToVar 
{
private :
     T1 m_source_vars_list;
     T2 m_dest_vars_list;
public:
    int Add(T1 source_node, T2 dest_node);
    VarToVar();
    virtual ~VarToVar();

};

//函数实现体

template<class T1, class T2>
VarToVar<T1, T2>::VarToVar()
{

}

template<class T1, class T2>
VarToVar<T1, T2>::~VarToVar()
{

}

template<class T1, class T2>
int VarToVar<T1, T2>::Add(T1 source_node, T2 dest_node)
{
     return FALSE;
}

//调用

VarToVar<int, int > a;    //用int 模板的类 示例化 a 

a.Add(3,4);

http://zhanyonhu.blog.163.com/blog/static/1618604420083167842277/

几点注意

  如果在全局域中声明了与模板参数同名的对象函数或类型,则该全局名将被隐藏。

在下面的例子中tmp 的类型不是double 是模板参数Type

typedef double Type;
template <class Type>

Type min( Type a, Type b )
{
    //tmp类型为模板参数?Type
    //不是全局?typedef

    Type tmp = a < b ? a : b;

    return tmp;
}

②  在函数模板定义中声明的对象或类型不能与模板参数同名

template <class Type>

Type min( Type a, Type b )
{

    //错误:重新声明模板参数?Type
    typedef double Type;
    Type tmp = a < b ? a : b;
    return tmp;
}

  模板类型参数名可以被用来指定函数模板的返回位

// ok: T1 表示 min() 的返回类型
// T2 和 T3 表示参数类型

template <class T1, class T2, class T3>

T1 min( T2, T3 );

④  模板参数名在同一模板参数表中只能被使用一次,但是模板参数名可以在多个函数模板声明或定义之间被重复使用

// 错误: 模板参数名 Type 的非法重复使用

template <class Type, class Type>

Type min( Type, Type );

 

// ok: 名字 Type 在不同模板之间重复使用

template <class Type>

Type min( Type, Type );

template <class Type>

Type max( Type, Type );

⑤  如果一个函数模板有一个以上的模板类型参数则每个模板类型参数前面都必须有关键字class 或typename

// ok:关键字typename和class可以混用
template <typename T, class U>

T minus( T *, U );

//错误:必须是?<typename T, class U>或<typename T, typename U>
template <typename T, U>

T sum( T *, U );

 为了分析模板定义编译器必须能够区分出是类型以及不是类型的表达式对于编译器来说它并不总是能够区分出模板定义中的哪些表达式是类型例如如果编译器在模板定义中遇到表达式Parm::name 且Parm 这个模板类型参数代表了一个类那么name 引用的是Parm 的一个类型成员吗.

template <class Parm, class U>
Parm minus( Parm *array, U value )
{

    Parm::name *p;
    // 这是一个指针声明还是乘法乘法
}

编译器不知道name 是否为一个类型因为它只有在模板被实例化之后才能找到Parm 表示的类的定义为了让编译器能够分析模板定义用户必须指示编译器哪些表达式是类型表达式告诉编译器一个表达式是类型表达式的机制是在表达式前加上关键字typename 例如如果我们想让函数模板minus()的表达式Parm::name 是个类型名因而使整个表达式是一个指针声明我们应如下修改

关键字typename 也可以被用在模板参数表中以指示一个模板参数是一个类型

template <class Parm, class U>

Parm minus( Parm* array, U value )

{

typename Parm::name * p; // ok: 指针声明

}

 如同非模板函数一样函数模板也可以被声明为inline 或extern 应该把指示符放在模板参数表后面而不是在关键字template 前面

// ok: 关键字跟在模板参数表之后

template <typename Type>

inline

Type min( Type, Type );

源地址:http://blog.renren.com/GetEntry.do?id=503757691&owner=231887749

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值