c++模板

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

通过宏实现
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;
}

这里写图片描述

函数重载实现加法函数

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;
}

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

函数模板

    实际是建立了一个通用函数,函数返回类型和形参类型不具体指定,
用一个虚拟的类型代表,这个通用函数成为函数模板。
一般格式        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;
}

这里写图片描述

模板类的实例化

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

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

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值