第十六课(模板)

1,模板和泛型

泛型编程是指独立与任何类型的方式编写代码;泛型编程和面向对象编程,都依赖与某种形式的多态.面向对象编程的多态性在运行时应用于存在继承关系的类.一段代码可以忽略基类和派生类之间的差异.在泛型编程中,编写的代码可以用作多种类型的对象.面向对象编程所依赖的多态性称为运行时多态性,泛型编程所依赖的多态性称为编译时多态性或参数式多态性;

模板是泛型编程的基础,模板是创建类或者函数的公式;

模板是一种对类型进行参数化的工具,有两种形式:函数模板和类模板;

2,函数模板

针对仅参数类型不同的函数;

3,类模板

针对仅数据成员和成员函数类型不同的类;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uO7OnoDy-1616052576723)(C:\Users\daili\Desktop\CSDN笔记\相关图片\模板图例.png)]

4,函数模板

例子:
//实现两个对象的求和
//特点:功能相同,只有参数类型不同--将类型参数化
template<typename Type,typename Type2>
//定义模板参数列表
Type add(Type a, Type2 b)
{
	return a + b;
}

5,函数模板调用

`显示类型调用: 需要在函数调用处的函数名后面加上类型参数;

如: fun(2,6);

`自动类型推导: 根据参数的类型进行推导,但是两个参数的类型必须一致,否则会报错;

如: fun(2,3);

注意:当需要两个及以上的参数,可以多些几个模板类型;

例子:
template <typename A,typename B>
auto fun(A a,B b)
{
}

6,函数模板和普通函数

1,当函数模板和普通函数参数都符合时,优先选择普通函数;

2,若想显示使用模板函数,则在函数名后加上<>类型列表;

3,如果函数模板产生更好的匹配,则使用函数模板;

注意:模板的声明与定义只能放在头文件中,对于函数模板声明和定义,文件会有一个新的名字-即hpp文件;

7,类模板

类模板与函数模板的定义和使用类似.当有两个或多个类功能相同,仅数据类型不同,就需要模板类;

案例://模板的参数类型定义写在类定义之前,在类里面任何位置都可使用;
template<typename T>
class V
{
    public:
    V(T a):_a(a){}
    private:
    T _a;
}

`类模板用于实现类所需数据的类型参数化;

`类模板在表示如数组,表,图等数据结构十分重要,这些数据结构的表示和算法不受所包含的元素类型的影响(STL);

8,继承中的类模板–类模板派生普通类

子类被模板类继承时,需要写父类的数据类型(数据类型的本质:如何分配内存空间);

案例:
template<typename H>
class A
{
    public:
    A(H h):v(h){}
    void a()
    {
        cout<<v<<endl;
    }
    protected:
    H v;
};
class B:public A<int>//指定具体类型
{
    public:
    using A<int>::A;
};

9,类模板–派生模板类

案例:
template<typename H>
class A
{
    public:
    A(H h):v(h){}
    void a()
    {
        cout<<v<<endl;
    }
    protected:
    H v;
};
template<typename N>
class B:public A<N>//指定具体类型
{
    public:
    using A<int>::A;
};

注意:子类在使用父类中的成员时,会提示找不到标识符:

解决方法:

1,通过this指针访问:this->父类成员;

2,通过父类访问:父类名<数据类型>::父类成员;

10,模板特化

模板函数的参数只能传入类类型的参数;特化函数的参数只能传入对应的参数类型;

案例:
//模板函数
template<typename T>
int compare(T a,T b)
{
    return a==b?0:(a>b?1,-1);
}
模板函数支持int...等类型的计算,但不能用来比较字符串(char*),因为这个函数比较的是串指针,而不是字符串本身;
//特化函数
template<>//必须写,否则成了重载函数
int compare(const char* a,const char* b)
{
    return strcmp(str1,str2);//可以比较字符串了;
}

11,array类

C++中提供了一个静态数组类:头文件;

例子:
array<int,99> _ad{0};
自己实现这个类:
template<typename Type,size_t t>
class Array
{
    public:
    Type& operator[](int i)
    {
        return _array[i];
    }
    private:
    Type _array[t];//[]里面只能放常量
};
必须知道的类型别名:
size_t :unsigned int
DWORD :unsigned long
WORLD :unsigned short

12,using其他用法

using和typedef有类似的作用,而且能够完全替代typedef;

案例:
typedef int INT;
using INT = int;

typedef void (*pFun)();
using Pfun =void(*)();

template<typename T>
typedef Array<T,9> arr;//error 

template<typename T>
using arr=Array<T,9>;//true