泛型编程和模板

01 泛型编程

所谓的泛型编程,指的就是编写程序的时候,是独立于任何特定的类型来编写代码

那么什么叫做独立于任何特定的类型呢?
        如:

                设计一个数组类型(class Array),这个数组有可能只能存放 int 类型的元素,但是你在代码中使用这个数组的时候却不一定总是 int 类型的元素,可能需要数组能够存放其他类型的元素

                也就是说,数组是一个通用的概念,不应该局限于某一种特定的类型

                所以,数组元素的类型,应该可以独立表示,类似于函数的参数,可以在实例化数组的时候,可以传递一个类型参数指定数组中的元素类型

                

如果设计出来的数组,能够存放任意类型的元素,那么这就是泛型编程(程序逻辑和类型没有关系,可以应用于任何类型)

泛型编程如何实现呢?
        使用模板实现

02 模板

在C++中使用模板来实现泛型编程,或者说使用模板来表示一个通用的概念
        模板允许我们在定义函数或者类的时候,将类型作为参数(代码里面不包含具体的类型)
        编译器可以根据你提供的类型自动生成特定的函数或者类
    
        如:
                指定数组元素类型为double,编译器就可以根据模板自动生成一个存放double类型元素的数组类
        指定数组元素类型为int,编译器就可以根据模板自动生成一个存放int类型元素的数组类
        指定数组元素类型为string,编译器就可以根据模板自动生成一个存放string类型元素的数组类
        ...

        简单的说,模板就是用来创建一个类或者一个函数的公式(蓝图)

        如:
                以前我们创建一个类,可以用来实例化对象
                现在我们可以定义一个模板,可以用来实例化一个具体的类型,再使用创建出来的类实例化对象

        根据一个模板创建一个类/函数的过程叫做实例化

   

模板可以分为两种:
        a. 函数模板,可以用来创建具体类型的函数
        b. 类模板,可以用来创建具体类型的类

03 函数模板

语法规则:

        template<typename T1, typename T2 ......>  // 模板头

        返回值类型  函数名(参数列表) {

                // 函数体;

        }

T:类型参数的形参名,在后面的函数体中,可以直接使用这个类型参数
如果该函数模板涉及到多个类型参数,只需要在尖括号中以逗号隔开即可!

编译器会自动的推导参数类型去匹配函数模板

    
类型参数化!!!

对于函数模板,编译器可以自动推导参数的类型

例子:
        定义一个函数模板,用于计算两个对象的和

04 类模板

C++中除了支持函数模板还支持类模板(class template)
    
函数模板中定义的类型参数(T)可以在函数的声明和定义中使用
类模板中定义的类型参数可以在类的声明和类的实现中使用,类模板的目的是将数据的类型参数化

   

声明类模板的语法:
        template<typename T1, typename T2>
        class 类名 {
                public:

                        ...
                private:
                        ...
                protected:
                        ...
        };

类模板和函数模板都是以template开头,后面跟上类型参数,类型参数不能为空,多个类型参数使用逗号隔开
一旦声明了类模板,就可以将类型参数用于类的成员变量和成员函数

   

类模板的使用方式:
        调用函数模板只需要提供函数值,编译器会自动的根据用户提供的值去推导值的类型,
再自动生成相应的函数版本
     
       
但是我们在使用类模板的时候,必须显示的指定目标参数
        因为:
        Array a;  没有任何数据可以表示类型,必须明确的指定参数
        ========>
        格式:
            
    模板类名<实际类型1, 实际类型2> 对象名;

        SeqStack<int> s; // 实例化一个栈对象,栈中的元素都是int
        SeqStack<string> s1; // 实例化一个栈对象,栈中的元素都是string 
        SeqStack<Test> s2; // 实例化一个栈对象,栈中的元素都是Test
        ...
        vector<int> v;
        ...


注意:

1. 如果模板类的成员函数在类外实现(声明和定义分开),则该成员函数必须有模板声明,并且作用域也必须指定模板参数

//构造函数
template<typename DataType>
Stack<DataType>::Stack(int capacity) : m_top{-1}, m_capacity{capacity},
                                m_data{new DataType[capacity]} {
    cout << "constructors" << endl;
    // 为栈开辟存储元素的空间
    // m_data = new DataType[capacity];
}

// 析构函数
template<typename DataType>
Stack<DataType>::~Stack() {
    cout << "de-structors" << endl;
    delete [] m_data;
}

// 拷贝构造函数 
template<typename DataType>
Stack<DataType>::Stack(const Stack &oth) {
    cout << "copy-constructors" << endl;
    m_top = oth.m_top;
    m_capacity = oth.m_capacity;
    m_data = new DataType[m_capacity];
    // memcpy:内存拷贝 src:源地址,dest:目标地址,count:拷贝字节数
    memcpy(m_data, oth.m_data, sizeof(DataType) * m_capacity);
}   

2. 如果模板函数和模板类的声明和定义分开,只能写在同一个文件中的不同位置,不能把声明和定义写在不同的文件中,也就是说,模板的声明和定义必须在同一个文件中,意味着模板实现的功能必须开源

3. 在模板声明中,使用关键字typename来说明类型参数的名字
    但是在早期的C++中,曾经使用的关键字叫做class

    在新标准中,建议使用typename

如:
template<class T1, class T2>
class 类名 {
    private:
        ......
    protected:
        ......
    public:
        ......
};

05 模板的特化

解决开发过程中由于要对特殊类型做特殊的处理,不能直接使用函数模板(针对特定类型应该使用特定版本)

C++中的模板分为类模板和函数模板,虽然它引进到C++标准中的时间不是很长,但是却得到了广泛的应用,这一点在STL中有着充分的体现

目前,STL在C++社区中得到了广泛的关注,应用和研究
理解和掌握模板是学习、应用和研究以及扩充STL的基础(STL就是使用模版实现的模板函数和模板类),而STL模板实例中又充斥着大量的模板特化和偏特化

06 类模板特化

有时为了需要,针对特定的类型,需要对模板进行特化,也就是特殊处理
例如:

        stack类模板针对bool类型,因为实际上bool类型只需要一个二进制位就可以对其进行存储,使用一个字或者一个字节都是浪费存储空间的
// Stack类模板的实现

template<class T>

class Stack {

        // 使用T类型

};

================>

针对数据类型为bool的栈进行特殊化处理的类模板

template<>

class Stack<bool> {

        // 针对数据为bool的特殊处理

};

上述定义中template<>告诉编译器这是一个特化(特殊化)的模板

当用户使用 Stack<bool> bs; 的时候会使用下面的特化模板
模板的特化和偏特化_模板的特化与偏特化,就测测模板的基础编程-优快云博客

07 函数模板的特化

08 模板特化时的匹配规则

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值