曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 2726|回复: 1
打印 上一主题 下一主题

类模板

[复制链接]

716

主题

734

帖子

2946

积分

超级版主

Rank: 9Rank: 9Rank: 9

积分
2946
跳转到指定楼层
楼主
发表于 2013-7-30 00:51:50 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
函数模板 函数模板可以自动生成在实参类型或返回值类型不同的函数,对于类来说也有类似机制。

类模板本身不是类,而是编译器用来生成类代码的一种方法。类模板和函数模板一样,也是通过指定模板中尖括号内的形参类型来确定希望生成的类。以这种方式生成的类称为“类模板的实例”,根据模板创建类的过程称为“实例化模板”。比如下面定义一个类模板:
[C++] 纯文本查看 复制代码
 template <class T> class CExample {
T m_Value;
...
}

比如将 T 指定为 int 后,可有 class CExample { int m_value; ... } 。
将 T 指定为 double 后,可有 class CExample { double m_Value; ... }。
将 T 指定为 CBox (一个类类型),可有 class CExample { CBox m_Value; ... } 。

下面这个简单的类模板示例说明如何定义和使用类模(为了不使问题复杂化,省略许多考虑的因素):
[C++] 纯文本查看 复制代码
// CSamples class template definition 
template <class T> class CSamples 
{
  public:
    // Constructors
    CSamples(const T values[], int count);
    CSamples(const T& value);
    CSamples(){ m_Free = 0; }

    bool Add(const T& value);          // Insert a value
    T Max() const;                     // Calculate maximum

  private:
    T m_Values[100];                   // Array to store samples
    int m_Free;                        // Index of free location in m_Values
};

// Constructor template definition to accept an array of samples
template<class T> CSamples<T>::CSamples(const T values[], int count)
{
  m_Free = count < 100? count:100;     // Don't exceed the array
  for(int i = 0; i < m_Free; i++)
    m_Values[i] = values[i];           // Store count number of samples
}

// Constructor to accept a single sample
template<class T> CSamples<T>::CSamples(const T& value)
{
  m_Values[0] = value;                 // Store the sample
  m_Free = 1;                          // Next is free
}

// Function to add a sample
template<class T> bool CSamples<T>::Add(const T& value)
{
  bool OK = m_Free < 100;              // Indicates there is a free place
  if(OK)
    m_Values[m_Free++] = value;        // OK true, so store the value
  return OK;
}

// Function to obtain maximum sample
template<class T> T CSamples<T>::Max() const
{
  T theMax = m_Free ? m_Values[0] : 0; // Set first sample or 0 as maximum
  for(int i = 1; i < m_Free; i++)      // Check all the samples
    if(m_Values[i] > theMax)
      theMax = m_Values[i];            // Store any larger sample
  return theMax;
}

在这个类模板里,也定义了模板的成员函数。有时我们希望将类模板成员函数的定义放在模板定义的外部,比如 Max() ,创建时必须使用模板类的名称加上尖括号内的形参,以标识函数模板所属的类模板。

注意:作用域解析运算符之前只能使用附带形参名称 T 的类模板名。这是必须的 --- 形参对于识别出该模板生成的函数属于哪个类非常重要。类模板的类型是 CSamples<T> ,其中 T 是在创建类模板实例时指定的类型。在类模板中插入指定的类型,从而生成类定义。还将其插入函数模板中,从而生成本类中 Max() 函数的定义。每个根据类模板生成的类都需要有自己的 Max() 函数的定义。构造函数和析构函数的情况与此类似。

根据类模板创建对象
当使用函数模板定义的函数时,编译器能够根据使用的实参类型生成函数。函数模板的类型形参是通过使用特定的函数隐式确定的。也就是说,指定了实参的类型之后,那么形参会根据实参的类型来确定,但这个过程是隐式的。

然而类模板有些不同,为了以类模板为基础创建对象,必须在声明中指定类名后面的类型形参。比如,声明一个 CSample<> 对象来处理 double 类型的样本,需要将声明写成 CSample<double> myData(10.0); 。

测试代码:
[C++] 纯文本查看 复制代码
// Using a class template
#include <iostream>
using std::cout;
using std::endl;

class CBox                             // Class definition at global scope
{
  public:
    // Constructor definition
    CBox(double lv = 1.0, double wv = 1.0, double hv = 1.0): m_Height(hv)
    {
      m_Length = lv > wv? lv: wv;      // Ensure that 
      m_Width = wv < lv? wv: lv;       // length >= width
    }

    // Function to calculate the volume of a box
    double Volume() const
    {
      return m_Length*m_Width*m_Height;
    }

    // Operator function for 'greater than' which
    // compares volumes of CBox objects.
    int CBox::operator>(const CBox& aBox) const
    {
      return this->Volume() > aBox.Volume();
    }

    // Function to compare a CBox object with a constant
    int operator>(const double& value) const
    {
      return Volume() > value;
    }

    // Function to add two CBox objects
    CBox operator+(const CBox& aBox) const
    {
      // New object has larger length & width, and sum of heights
      return CBox(m_Length > aBox.m_Length? m_Length:aBox.m_Length,
                  m_Width > aBox.m_Width? m_Width:aBox.m_Width,
                  m_Height + aBox.m_Height);
    }

    // Function to show the dimensions of a box
    void ShowBox() const
    {
      cout << m_Length << " " 
           << m_Width  << " " 
           << m_Height << endl;
    }

  private:
    double m_Length;                   // Length of a box in inches
    double m_Width;                    // Width of a box in inches
    double m_Height;                   // Height of a box in inches
};
// CSamples class template definition 
template <class T> class CSamples 
{
  public:
    // Constructors
    CSamples(const T values[], int count);
    CSamples(const T& value);
    CSamples(){ m_Free = 0; }

    bool Add(const T& value);          // Insert a value
    T Max() const;                     // Calculate maximum

  private:
    T m_Values[100];                   // Array to store samples
    int m_Free;                        // Index of free location in m_Values
};

// Constructor template definition to accept an array of samples
template<class T> CSamples<T>::CSamples(const T values[], int count)
{
  m_Free = count < 100? count:100;     // Don't exceed the array
  for(int i = 0; i < m_Free; i++)
    m_Values[i] = values[i];           // Store count number of samples
}

// Constructor to accept a single sample
template<class T> CSamples<T>::CSamples(const T& value)
{
  m_Values[0] = value;                 // Store the sample
  m_Free = 1;                          // Next is free
}

// Function to add a sample
template<class T> bool CSamples<T>::Add(const T& value)
{
  bool OK = m_Free < 100;              // Indicates there is a free place
  if(OK)
    m_Values[m_Free++] = value;        // OK true, so store the value
  return OK;
}

// Function to obtain maximum sample
template<class T> T CSamples<T>::Max() const
{
  T theMax = m_Free ? m_Values[0] : 0; // Set first sample or 0 as maximum
  for(int i = 1; i < m_Free; i++)      // Check all the samples
    if(m_Values[i] > theMax)
      theMax = m_Values[i];            // Store any larger sample
  return theMax;
}

int main()
{
  CBox boxes[] = {                          // Create an array of boxes
                   CBox(8.0, 5.0, 2.0),     // Initialize the boxes...
                   CBox(5.0, 4.0, 6.0),
                   CBox(4.0, 3.0, 3.0)
                 };

  // Create the CSamples object to hold CBox objects
  CSamples<CBox> myBoxes(boxes, sizeof boxes / sizeof CBox);

  CBox maxBox = myBoxes.Max();              // Get the biggest box
  cout << endl                              // and output its volume
       << "The biggest box has a volume of "
       << maxBox.Volume() << endl;
  return 0;
}

输出结果:
The biggest box has a volume of 120

注意:当创建类模板的实例时,不要认为用于创建函数成员的那些函数模板的实例都被创建。编译器只创建程序中实际调用的那些函数的模板实例。事实上,函数模板甚至可以包含错误的编码,只要不调用到这些错误的编码,编译器就不会报错。比如在上面的示例中,试着给 Add() 模板引入几个错误(比如在其中乱敲入一些字符),该程序仍然能够编译运行,因为它没有调用 Add() 函数。

716

主题

734

帖子

2946

积分

超级版主

Rank: 9Rank: 9Rank: 9

积分
2946
沙发
 楼主| 发表于 2013-7-30 10:17:40 | 只看该作者

有多个形参的类模板

在类模板中使用多个形参,只需要简单的扩展上面单个形参的示例即可,比如:
[C++] 纯文本查看 复制代码
template <class T1, class T2> class CSamplesClass {
// Class data members

private:
    T1 m_Value1;
    T2 m_Value2;

... ...
};

类模板中的形参类型不受限制。我们还可以在类定义中使用一些需要以常量或常量表达式进行替换形参,比如模板的定义可以写成:
template <class T, int size> class CSamples
{
... ...
};
然后可以像下面声明一个实例:
CSamples<CBox, 3> Myboxes (boxes, sizeof boxes / sizeof CBox);

也可以这样写:
CSamples<CBox, sizeof boxes / sizeof CBox> Myboxes (boxes, sizeof boxes / sizeof CBox);

但要注意使用包含比较运算符的表达式,如:
CSample<aType, x > y ? 10 : 20 > MyType();
这样写不正确,因为大于号也可以被解释成右尖括号,所以上面这条语句应该写成:
CSample<aType, (x > y ? 10 : 20) > MyType();
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2024-5-17 08:30 , Processed in 0.072063 second(s), 22 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表