C++模板

一 定义

函数模板:定义用来生成一组具体函数配方的代码。

 

模板是对具有相同特性的函数或类的再抽象。

1.它是一种参数化多态性的工具,可以为逻辑功能相同 而类型不同的程序提供一种代码共享的机制。

2.一个模板并非一个实实在在的类或函数,仅仅是一个 类或函数的描述,是参数化的函数和类。

3.模板分为函数模板和类模板,通过参数实例化可以再 构造出具体的函数或类,称为模板函数和模板类。

 

二 函数模板和 模板函数

template <模板参数表 > 返回值类型 函数名 (参数表) { 函数体 }

// 使用max( )函数模板的位置范例
#include <iostream>
using std::cout;
using std::endl;
template <class T>
T max(T x[], int len)//注意前后连在一起
{
    T maxnumber = x[0];
    for (int i = 0; i < len; i++)
        if (maxnumber < x[i])
            maxnumber = x[i];
    return maxnumber;
}
int main(void)
{
    int small[] = { 1, 24 , 34 , 22 };
    long medium[] = { 23, 245, 123, 1, 234, 2345 };
    double large[] = { 23.0, 1.4, 2.456, 345.5, 12.0, 21.0 };
    int lensmall = sizeof small / sizeof small[0];
    int lenmedium = sizeof medium / sizeof medium[0];
    int lenlarge = sizeof large / sizeof large[0];
    cout << endl << max(small, lensmall);
    cout << endl << max(medium, lenmedium);
    cout << endl << max(large, lenlarge);
    cout << endl;
    return 0;
}
/*
34
2345
345.5
*/

一般情况下typename和class基本没有什么区别。

 

  函数模板

当编译系统在程序中发现有与函数模板中相匹配的函 数调用时,便生成一个重载函数,该重载函数的函数 体与函数模板的函数体相同。

该重载函数称为模板函数。它是函数模板的一个具体 实例,只处理一种惟一的数据类型。

// 重载模板函数实例,例题8.2
#include <iostream>
#include <string.h>
using namespace std;
template <typename T> T Max(T a, T b)
{
    return a > b ? a : b;
}
char * Max(char *pa, char *pb)
{
    return strcmp(pa, pb) ? pa : pb;
}
int main()
{
    cout << Max(10, 20) << endl;
    cout << Max("Hello", "Fellow") << endl;
    cin.ignore(); return 0;
}

为什么不直接用模板函数,而是 重载模板函数的理由? 答:因为字符串的比较方法是不 同的,无法使用模板函数,必须 重载

 

模板函数的重载的又一示例

// 模板函数与学生类的实例,例题8.3
#include <iostream>
#include <string.h>
using namespace std;
template <typename T> T Max(T a, T b)
{
    return a > b ? a : b;
}
class Student
{
    int number;
    char name[20];
public:Student(int i, char *s)
{
    number = i;
    strcpy(name, s);
}
       bool operator>(Student &st) //重载运算符>
       {
           return number > st.number; //返回成员number的比较结果
       }
       void Print()
       {
           cout << "Number: " << number << endl;
           cout << "Name: " << name << endl;
       }
};
int main()
{
    Student st1(12, "Li"), st2(13, "Zhang"), st3(0, "");
    st3 = Max(st1, st2);
    st3.Print();
    cin.ignore();
    return 0;
}
/*
Number: 13
Name: Zhang

*/

三 类模板和 模板类

类模板:不是类,是编译器用来生成类代码的类的框架。 用类模板创建出来的类被称为类模板的实例。

template <类型参数表> 返回值类型 类模板名 类型名表::函数名(参数表) { 函数体 }

 

类模板的使用

类模板名 <实际的类型>

类模板名 <实际的类型> <对象名>[(实际参数表)];CSamples myData(10.0);

 

// 使用CSample的范例程序
#include <iostream>
using namespace std;
// 定义一个箱子类
class CBox
{
public:
    // 构造函数:确保长比宽的数值大
    CBox(double lv = 1.0, double wv = 1.0, double hv = 1.0) :m_Height(hv)
    {
        m_Length = lv > wv ? lv : wv;
        m_Width = wv < lv ? wv : lv;
    }
    double Volume() const // 计算体积函数
    {
        return m_Length * m_Width*m_Height;
    }// >重载:比较CBox类型的两个对象
    int CBox::operator>(const CBox& aBox)const
    {
        return this->Volume() > aBox.Volume();
    }
    // >重载:比较CBox类型对象和double数据
    int operator>(const double& value) const
    {
        return Volume() > value;
    }
    CBox operator+(const CBox& aBox) const
    {
        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);
    }void ShowBox()const
    {
        cout << m_Length << " "
            << m_Width << " "
            << m_Height << endl;
    }
private:
    double m_Length;
    double m_Width;
    double m_Height;
};// 定义Csample类模板
template <class T>
class CSamples
{
public:
    CSamples(const T values[], int count);
    CSamples(const T& value);
    CSamples() { m_Free = 0; }
    bool Add(const T& value);
    T Max() const;
private:
    T m_Values[100];
    int m_Free;
};//接受数组形式样本数据的构造函数
template <class T>
CSamples<T>::CSamples(const T values[], int count)
{
    m_Free = count < 100 ? count : 100;
    for (int i = 0; i < m_Free; i++)
        m_Values[i] = values[i];
}
//接受单个样本数据的构造函数
template <class T>
CSamples<T>::CSamples(const T& value)
{
    m_Values[0] = value;
    m_Free = 1;
}//添加一个样本数据成员函数
template <class T>
bool CSamples<T>::Add(const T& value)
{
    bool OK = m_Free < 100;
    if (OK) m_Values[m_Free++] = value;
}
//提取最大样本数据的成员函数
template <class T>
T CSamples<T>::Max() const
{
    T theMax = m_Free ? m_Values[0] : 0;
    for (int i = 1; i < m_Free; i++)
        if (m_Values[i] > theMax)
            theMax = m_Values[i];
    return theMax;
}int main()
{
    CBox boxes[] = { CBox(8.0, 5.0, 2.0), CBox(5.0, 4.0, 6.0),
 CBox(4.0, 3.0, 3.0) };
    //使用数组初始化一个可以存储CBox对象的CSamples对象
    CSamples <CBox> myBoxes(boxes, sizeof(boxes) / sizeof(CBox));
    //计算最大的箱子
    CBox maxBox = myBoxes.Max();
    //输出结果
    cout << endl
        << "The biggest box has a volume of "
        << maxBox.Volume()
        << endl;
    cin.ignore(); return 0;
}
/*
The biggest box has a volume of 120
*/

 

  类模板的使用的注意事项

创建类模板的实例时,编译器只创建 程序中实际调用 的成员函数的模板实例;不能理解成用于创建函数成员的 那些函数模板的实例也将被创建。

因此,函数模板甚至可以包含编译错误,而且只要不调 用该模板生成的成员函数,编译器不会有什么抱怨;

例如, 在前面的例子中的Add( )成员的模板中引入错误,该程序 仍然可以编译和执行。

 

一个小问题:CBox类的构造函数被调用了多少次? 答案是103次!

主函数中创建了包含3个CBox对象的数组,发生3次调 用;

其后创建了一个容纳这些对象的CSamples对象,但 CSamples对象包含的数组有100个CBox类型的变量,因此 需要再调用默认构造函数100次。

 

  使用包含多个形参的类模板

如这样的类模板

template Class CExampleClass { private: T1 m_Value1; T2 m_Value2; …… };

posted @ 2019-12-04 23:20  TheDa  阅读(312)  评论(0编辑  收藏  举报