C++模版

转载 2008年10月03日 09:55:00

简介

只有使用C++语言的少数用户才努力尝试去理解模板的基本原理。然而那些希望去探索更多高级用法的人往往发现自己需要努力去理解模板是如何被语言所支持的,因为缺乏明确的说明。一个很大的问题在于一些工具只实现了C++标准的一个子集。本文将指出它们共同的缺陷并深入剖析如何使用C++模板快速产生可重用和高效的代码。

模板功能应用的典型是通过一系列模板类形成的完整类库,特别是STLATL。标准C++(STL)提供了很多可重用和灵活的类及算法,而ATL则是使用C++进行COM编程的事实标准。要掌握这些及其它的模板库,理解模板是如何工作的这一基础是非常重要的。

函数模板

int main()
{
    0 cout<<add(2,3)<<endl;
    1 cout<<add(2.1,3)<<endl;
    2 cout<<add(2,3.2)<<endl;
    3 cout<<add(2.2,3.3)<<endl;
    4 cout<<add("hello eone ","world")<<endl;
    return 0;
}

     也可以通过宏定义#define add(a,b) ((a)+(b))来实现,但是指针(字符串)不能直接相加.对于2,3,4需要进行模板特化.

通过重载函数,我们能够完成多种不同数据类型的相同操作。要实现两个double数值的加法和两个整数类型的加法,我们可以使用一个重载函数:

  int add(const int x, const int y)

  {

    return x + y;

  }

  double add(const double x, const double y)

  {

    return x + y;

  }

这时,编译器将根据它们的参数正确地解决这一问题。

//    调用int add(const int, const int);

const int z1 = add(3, 2);

      //    调用double add(const double, const double);

      const double z2 = add(3.0, 2.0);

如果我们需要处理其它类型,我们就不得不提供其他函数重载。对每个不同的数据类型实现一个函数重载,它们都遵循相同的模式,每当我们需要调用针对某一数据类型的函数时,原则上编译器为我们生成相应的代码。而一个模板函数则以如下方式实现:

  template<class T>

  const T add(const T &t1, const T &t2)

  {

    return t1 + t2;

  }

从概念上来说,编译器通过模板关键字(后面跟随着模板由一或多个模板参数构成的参数列表)来识别模板。当为某一具体类型调用add时,编译器将根据模板定义并用给定的类型替换出现在模板中的参数。在这个例子中,模板参数列表由一个独立的类型模板参数T构成。使用一个模板函数替代函数重载,编译器可以自动为所需的新类型生成代码

我们可以对任何拥有+操作符定义的类型使用add模板。假设一个自定义的String类提供了字符串连接并知道如何将自身写入到std::ostream。因为String与该模板函数兼容,因此我们可以调用它来实现字符串相加:

  //    示例字符串

  const string strBook("book");

  const string strWorm("worm");

//    显示 "bookworm".

  cout << add(strBook, strWorm) << endl;

Seeing that we intended to add two String values, the compiler will generate the appropriate add function on our behalf, which would look something like:

  const String add(const String &t1, const String &t2)

  {

    return t1 + t2;

  }

显式实例化

调用模板函数时,编译器将先把正确的类型实例化模板。虽然标准允许显式模板实例化,然而并非所有厂商都能够正确地实例它。例如,Visual C++ 6.0 会潜在地调用错误的函数::

  template<class T>

  int getSize(void) {

    return sizeof(T);

  }

  //    输出4,应该为8

  cout << "double: " << getSize<double>() << endl;

//    输出4,正确

  cout << "int: " << getSize<int>() << endl;

跨平台代码设计者不希望依赖于显式模板函数实例化,除非有更好的编译器能够对它提供有效的支持

 

 

类似于函数模板,模板也可以应用于类。模板可以用于根据普通模式提供一系列类。如果我们需要一套完整的算术运算来补充add函数,我们可以考虑使用一个类。通过模板,它就可以根据类型参数化为一个普通类:

  template<class T>

  class CCalculator

  {

  public:

    CCalculator(const T &x, const T &y) : m_x(x), m_y(y){ }

    ~CCalculator(void){ }

     const T add(void){ return m_x + m_y; }

    const T sub(void){ return m_x - m_y; }

    const T mult(void){ return m_x * m_y; }

    const T div(void){ return m_x / m_y; }

    private:

    const T m_x;

    const T m_y;

  };

要实例化模板类,我们需要提供一个指定类型:

  //    创建一个整数计算对象

  CCalculator<int> calc(5, 2);

//    结果应该为 10

  const int z = calc.mult();

  

如函数模板一样,编译器为模板不同类型的引用创建不同的类。这为代码重用提供了一个强大的机制,允许单个模板用于任何兼容的数据类型

模板编辑模型

在编写模板类时,函数定义通常与它们的声明一起保存在头文件中,而不使用另外的.cpp文件。否则可能会导致链接错误。这是因为大多数编译器要求模板定义在以头文件为单位的转译单元中有效

这个行为的原因是模板只是一个模式,同样它们不直接产生代码(直到编译器遇到一个应用实例)。如果我们创建一个CCalculator<int> 实例并调用其中的某个类方法,编译器将需要找到函数定义。如果头文件中包含了该定义则一切都会是正确的。但是如果定义存在于.cpp文件中,编译器不能期望在此时找到匹配的模式并利用其产生所需的代码。然而,C++标准提供了一个机制对编译器进行辅助。Export关键字可以使通知编译器我们提供了一个分离的编辑模板:

  //    MyTemplateFunction.h

  template<class T>

  void myTemplateFunction(const T &t1);

//    MyTemplateFunction.cpp

  export template <class T>

  void myTemplateFunction(const T &t1)

  {

    ...

  }

  

现在,大多数编译器要求模板定义通过头文件包含被显式添加到转译单元,虽然标准期望能够独立定义于.cpp文件中。这两个不同的模板编辑模型即为包含模型和分离模型。在编写时,我所知的支持分离模型的唯一的编译器是Comeau C++Comeau 的使用了不少方法来实现对标准中所定义的export关键字用法,但目前也还只是beta版本而已

typename关键字

另一个与模板相关的关键字是typename关键字,它有两种用法。参数下面的模板类:

  template<class T>

  void myFunction(void)

  {

    // 这里可能会有问题

    T::x1 * x2;

  }

初次讲到的时候可能会以为myFunction声明了一个T::x1类型的指针变量x2。然而,这个函数也能够表示类T的成员变量x1与全局变量x2的二进制乘法操作。使用typename关键字可以告诉编译器某个未知标识符是一个类型:

  // T:x1 是一个类型,而x2是一个指针

  typename T:x1* x2;

第二种用法是在指定模板参数时替换class关键字:

  //    下面的两种方法是等效的...

  template<class T1, class T2>;

  template<typename T1, typename T2>;

标准允许以上任意一种方法,它们都是合法的。

成员函数模板

除了全局模板函数外,语言也支持成员模板函数:一个类可以拥有带有模板参数列表的成员函数。参考下面的非模板类,它的构造函数被模板化:

  class CTypeSize

  {

  public:

    template<class T>

    CTypeSize(const T &t1) :

      m_nSize(sizeof(t1))

    {

    }

    ~CTypeSize(void){ };

    int getSize(void) const{ return m_nSize; }

  private:

    const int m_nSize;

  };

当模板成员函数被调用时,编译器使用模板模式为给定类型生成代码。这种情况下,我们能够使用任意类型变量创建一个CtypeSize实例:

  //    显示12

  CTypeSize t1("Hello World");

  cout << t1.getSize() << endl;

  //    VC++6/Win32中显示8

  CTypeSize t2(7.0);

  cout << t2.getSize() << endl;

某些时候,成员模板是实现拷贝构造函数最有效的方法,参考一个只有一个交易会的简单容器类:

  template<class T>

  class CSingle

  {

  public:

    CSingle(const T &t1) : m_Value(t1) { }

    ~CSingle(void){ }

    T m_Value;

  };

它导致下面的问题:

  //    创建一个整数容器

  CSingle<int> x(7);

  //    这里需要一个拷贝构造...

  CSingle<double> y(x);

通过使用成员模板,拷贝构造就能够轻松完成:

  template<class S>

  CSingle(const CSingle<S> &s1) : m_Value(s1.m_Value) { }

当编辑器能够将类型T的实例转换为类型S时,这是可行的;这是因为double可以从一个整数构造。

总结

模板是C++的一个强大特征,它允许从数据类型中抽象出算法。本文介绍了模板定义和实例化的基础,包括函数、类及成员模板的区别。

c++模版实例化继承

100 99.9 SubSub released Sub released Object released #include using namespace std;templateclass Obj...
  • xiuye2015
  • xiuye2015
  • 2016年01月24日 21:26
  • 509

使用c++模板的优点和缺点

作为C++语言的新组成部分,模板引入了基于通用编程的概念。通用编程是一种无须考虑特定对象的描述和发展算法的方法,因此它与具体数据结构无关。但在决定使用C++模板之前,让我们分析一下使用模板的优缺点。 ...
  • chanlp129
  • chanlp129
  • 2014年03月16日 23:50
  • 3461

C++函数模板及实现原理

C++为我们提供了函数模板机制。所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来代表。这个通用函数就称为函数模板。 凡是函数体相同的函数都可以用这个模板来代替...
  • baidu_28312631
  • baidu_28312631
  • 2015年08月25日 12:50
  • 6285

C++——模版:类模版

需求分析: 学习类模版的使用: 编译环境: visual studio 2010 解决方案:返回: C/C++——模版相关知识...
  • qq_35162107
  • qq_35162107
  • 2017年05月19日 14:39
  • 155

C++标准模板库

分类: Linux c++开发 电子书 2013-09-11 21:21 802人阅读 评论(0) 收藏 举报 目录(?)[+] 作为C++标准库相当重要的一部分,S...
  • tangzhilinhk
  • tangzhilinhk
  • 2014年07月10日 11:48
  • 763

C++模板参数具体概念讲解

C++编程语言是一个功能强大的计算机应用语言,它的出现在一定程度上大大降低了开发人员的负担,提高了开发效率。我们在这里先来了解一下C++模板参数的相关概念。简单的说,可以把模板看作一种类型,函数模板也...
  • u013882737
  • u013882737
  • 2015年05月25日 15:21
  • 311

C++重复模板实例的处理

参考《深入浅出C++模板编程》 两个函数由同一模板生成,完全等价,则这两个函数为重复模板实例。C++对重复模板实例的解决方案是:在链接时识别及合并等价的模板实例。 示例代码 //----...
  • snowsnowsnow1991
  • snowsnowsnow1991
  • 2016年05月05日 23:12
  • 393

C++大整数模板 BigInteger

网上找的模板#include #include #include using namespace std;struct BigInteger{ int A[25]; enum{M...
  • SolarDomo
  • SolarDomo
  • 2016年08月13日 20:56
  • 1262

【C++】C++11特性:模板推导和循环区间

模板推导C++11在template编程的领域有很大的更新,功能愈发强大了,引入变参模板、外部模板等新功能,大大增强了模板编程的能力,其中新特性Tuple元组使用了变参模板特性。其中用的最多的,是模板...
  • lpsl1882
  • lpsl1882
  • 2016年10月02日 13:07
  • 356

C++ Template 基础篇(一):函数模板

C++ Template 基础篇(一):函数模板Template所代表的泛型编程是C++语言中的重要的组成部分,我将通过几篇blog对这半年以来的学习做一个系统的总结,本文是基础篇的第一部分。C Te...
  • lezardfu
  • lezardfu
  • 2017年02月24日 19:40
  • 2565
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C++模版
举报原因:
原因补充:

(最多只允许输入30个字)