欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

c++模板

程序员文章站 2022-06-01 14:05:38
...

如何编写一个通用的加法函数呢?

通过宏实现
1 没有参数检测,导致安全性不高
2 不能像函数进行调试,编译期间代码替换,当代码很长时会增加代码量
3 宏只能处理整数或枚举类型的数据,其他外置类型的数据处理不了

#include<iostream>
using namespace std;

#define ADD(x,y) ((x) + (y))

int main()
{
    cout<<ADD(1,3)<<endl;
    cout<<ADD(1.3,2.5)<<endl;
    cout<<ADD('A','G')<<endl;
    system("pause");
    return 0;
}

c++模板

函数重载实现加法函数

int Add(const int &_iLeft, const int &_iRight)
{
    return (_iLeft + _iRight);
}
float Add(const float &_fLeft, const float &_fRight)
{
    return (_fLeft + _fRight);
}

int main()
{
    cout << Add(1, 3) << endl;
    cout << Add(1.3f, 2.5f) << endl;
    system("pause");
    return 0;
}

这种方法的缺点
1 只要有新类型出现,就要实现相应函数
2 除类型外,所有函数的函数体相同,代码复用率不高
3 如果只是返回值类型不同,函数重载不能解决问题
4 一个方法有问题,所有的方法都有问题,不易维护

通过多态实现
使用公共基类,将需要用到的虚函数代码放在公共的基础类里面,通过基类的对象指针进行调用,派生类可重写也可不重写。

class B
{
public:
    virtual int add(int _x, int _y)
    {
        return (_x + _y);
    }
    virtual float add(float _x, float _y)
    {
        return (_x + _y);
    }
};
class INT_ADD :public B
{};
class FLOAT_ADD :public B
{};

int main()
{
    B *b;
    INT_ADD i;
    FLOAT_ADD f;

    b = &i;
    cout << b->add(1, 3) << endl;
    b = &f;
    cout << b->add(1.8f, 3.6f) << endl;

    system("pause");
    return 0;
}

借助基类虚函数编写缺点
1 写各种类型加法函数,只要有新类型旧需要重写对应函数
2 对于以后实现的许多派生类都必须调用各自特定的基类虚函数,代码维护困难

模板解决

模板分类: 函数模板 / 类模板 分别允许用户构造函数模板 、类模板

使用函数模板实现加法函数

template<typename T>
T ADD(T x, T y)
{
    return (x + y);
}
int main()
{
    cout << ADD(1, 3) << endl;
    cout << ADD(1.3, 2.5) << endl;
    system("pause");
    return 0;
}

c++模板
优点:利用模板可用显著减少冗余信息,能大幅节约程序代码,进一步提高面向对象程序的可重用性和可维护性

函数模板

    实际是建立了一个通用函数,函数返回类型和形参类型不具体指定,
用一个虚拟的类型代表,这个通用函数成为函数模板。
一般格式        template <typename 类型参数>
               返回类型  函数名  模板形参表

函数模板的使用

函数模板的实例化:
当我们调用函数模板时,编译器用函数实参来为我们推断模板实参,此模板实参为我们实例化一个特定的函数。

实例化:显示实例化, 隐士实例化

template <typename T>
T ADD(T x,T y)
{
    return (x+y);
}
int main()
{
    cout<<ADD(1,3)<<endl;//隐式实例化
    cout<<ADD<float>(1.3f,2.5f)<<endl;//显式实例化
    system("pause");
    return 0;
}

注意:自定义类型不能直接调函数模板进行实例化,除非自己实现重载

注意:模板被编译了两次
1 实例化之前,检查模板代码本身,查看是否出现语法错误
2 实例化期间,检查模板代码,查看是否所有调用都有效

模板函数的使用规则
模板函数可定义为内联函数

template <typename T>
inline T ADD(T x,T y)
{
    return (x+y);
}

inline关键字必须放在模板形参表之后,返回值之前,不能放在template之前
在template语句与函数模板定义语句之间不允许插入别的语句

函数模板不足:不能自动进行类型转换,需要生成代码,所以编译速度慢

模板参数
1 实参推演 :从函数实参确定模板形参类型和值
2类型形参转换

    1.   const转换
    接收const引用或const指针的函数可用分别用非const对象的引用和指针调用
template <typename T>
 T ADD(const T& x,const T& y)
{
    return (x+y);
}
    2.   数组或函数到指针的转换
    数组实参将当作指向其第一个元素,函数实参当作指向函数类型的指针
template <typename T>
T ADD(const T* x,const T* y)
{
    return (*x + *y);
}
int main()
{
    int a[5] = {0};
    int b[5] = {5,4,3,2,1};
    cout<<"a + b = "<<ADD(a,b)<<endl;
    system("pause");
    return 0;
}

模板参数的分类

    函数模板有两种类型参数:模板参数和调用参数
    模板形参:类型形参和非类型形参

函数模板的重载
1 同一般函数一样,函数模板也可用重载

template<typename T>
T Max(const T& left, const T& right)
{
    return left>right? left:right;
}
template<typename T>
T Max(const T& a, const T& b, const T& c)
{
    return Max(Max(a, b), c);
};
int main()
{
cout<<Max(1,2)<<endl;
cout<<Max(1.2,3.4,5.6)<<endl;
system("pause");
return 0;
}
运行结果        //2
            //5.6

注意:函数的所有重载版本的声明都应该位于该函数被调用位置之前

函数模板的特化(具体化)

1、有时候不是所有可能被实例化的模板都是合适的,某些情况下,通用模板定义对于某个类型可能是完全错误的,就需要对模板特例化(具体化)

template<typename T>
int Compare(T s1, T s2)
{
    if (s1 > s2)
    {
        return 1;
    }
    else if (s1 < s2)
    {
        return -1;
    }
    else
        return 0;
}
template<>//函数模板的特化
int Compare<const char*>(const char* s1, const char*s2)
{   
    return strcmp(s1,s2);
}
int main()
{
    const char* str1 = "abcd";
    const char* str2 = "ghf";
    cout << Compare(str1, str2) << endl;
    system("pause");
    return 0;
}

函数模板特化形式:
template<>
返回值 函数名 (参数列表)
{
//函数体
}
注意:特化的声明必须与特定的模板相匹配
给函数模板传参时一定要与特化参数列表中的参数格式一模一样,否则有可能即使写了特化,运行过程中也不会调用。

类模板
类模板 :以关键字temeplate开头,后接模板形参表
类模板格式: template

typedef int DataType;
//typedef char DataType;
class SeqList
{
private :
DataType* _data ;
int _size ;
int _capacity ;
};

【模板类实现顺序表】

template<typename T>
class Seqlist
{
public:
    Seqlist();
    ~Seqlist();
private:
    int _size;
    int _capacity;
    T* _data;
};

template <typename T>
Seqlist<T>::Seqlist()
:_size(0)
, _capacity(10)
, _data(new T[_capacity])
{}

template<typename T>
Seqlist<T>::~Seqlist()
{
    delete[]_data;
}
void test1()
{
    Seqlist<int> sl1;
    Seqlist<double>sl2;
}

c++模板

模板类的实例化

SeqList<int > sl1;
SeqList<double > sl2;

当定义上述两种类型的顺序表,编译器会使用int,double分别代替模板形参,重新编写Seqlist类,最后创建Seqlist和Seqlist的类