C++ 模板

1. 模板

模板可以让类或者函数支持一种通用类型,这种通用类型在实际的运行过程中可以使用任何数据类型,因此可以让程序员写出一些与类型无关的代码,这种编程方式也被称为"泛型编程"。

模板——是一段带有类型参数的程序代码,可以通过给这些参数提供一些类型来得到针对不同类型的具体代码。

  • 值和类型是数据的两个主要特征,它们在C++中都可以被参数化。
  • 数据的值可以通过函数参数传递,在函数定义时数据的值是未知的,只有等到函数调用 时接收了实参才能确定其值。——这就是值的参数化。
  • 数据的类型也可以通过参数来传递,在函数定义时可以不指明具体的数据类型,当函数 调用时,编译器根据传入的实参自动推断数据类型。——这就是类型的参数化(把类型 定义为参数)

模板通常有两种形式:

● 函数模板

● 类模板

1.1 函数模板

使一个函数支持模板编程,使函数支持通用数据类型。

函数模板——实际上是定义一个通用函数,它所用到的数据的类型(包括返回值类型、形参类型、局部变量类型)均被作为参数:不指定具体类型,而是用一个虚拟的类型来代替(实际上是用一个标识符来占位)。凡是函数体相同的函数都可以用 这个模板来代替,在函数调用时根据传入的实参来逆推出真正的类型。这个通用函数就称为函数模板。

通过函数模板实现类型参数化,即把类型定义为参数,从而实现代码复用。

可见:函数模板并不是一个可以直接使用的函数,它是可以产生多个函数的模板。

 

用法:

  1. template是声明模板的关键字,告诉编译器这是一个模板,开始泛型编程。
  2. 尖括号<>中的class是定义形参的关键字,用来说明其后的形参名为类型参数,(模板形参)。class可以用Typename关键字代替,两者没有区别。
  3. 模板形参(类属参数)不能为空(俗成约定用一个大写英文字母表示),且在函数定义部分的参数列表中至少出现一次。与函数形参类似,可以用在函数定义的各个位置:返回值、形参列表和函数体。
  4. 函数定义部分:与普通函数定义方式相同,只是参数列表中的数据类型要使用 尖括号<>中的模板形参名来说明。

实例化:

定义好的函数模板不可以直接使用,只相当于一个模具、规则,可使用不同类型的参数来调用,可减少代码的书写,提高代码复用性。

编译器会根据调用时的参数类型进行相应的实例化,即用具体的类型参数去替换函数模板中的模板参数,生成一个确定的具体类型的真正函数,才能实现运算操作。

 

比如:template<class T>

T add(T a,T b)

比如当调用 add(1,2) 时,形参T被替换成 int

当调用 add(1.5,2.2) 时,形参T被替换成 float

注意事项:

  1. 函数模板中的每一个类型参数在函数参数表中必须至少使用一次。
  2. 在全局域中声明的与模板参数同名的对象、函数或类型,在函数模板中将被 隐藏。
  3. 函数模板中定义声明的对象或类型不能与模板参数同名。
  4. 模板参数名在同一模板参数表中只能使用一次,但可在多个函数模板声明或 定义之间重复使用。
  5. 模板的定义和多处声明所使用的模板参数名不一定要必须相同。
  6. 函数模板如果有多个模板参数,则每个模板类型前都必须使用关键字typename 或class修饰。

函数模板实例:

#include <iostream>

using namespace std;

template<class T>   // 可以是class 也可以是typename

T add(T a,T b)
{
    return a+b;
}

//T add2(T a,T2 b)
//{
//    return a+b;
//}

int main()
{
    cout << "Hello World!" << endl;
    
    string a = "hello";
    string b = "world";
    cout << "add(1,2)= " << add(1,2) << endl;
    cout << "add(1.2,2.5)= " << add(1.2,2.5) << endl;
    cout << "add(a,b)= " << add(a,b) << endl;
    
    //    cout << "add2(1,2)= " << add2(1,2) << endl;
    //    cout << "add2(1,2.5)= " << add2(1,2.5) << endl;
    //    cout << "add2(1.2,2)= " << add2(1.2,2) << endl;
    
    return 0;
}

1.2 函数模板注意事项说明

(1)函数模板中的每一个类型参数在函数参数表中必须至少使用一次。例如:下 面的函数模板声明是不正确的:函数模板声明了两个参数T1与T2,但在使用 时 只使用了T1,没使用T2。

(2)在全局域中声明的与模板参数同名的对象、函数或类型,在函数模板中将被 隐藏。例如:在函数体内访问num是访问的T类型的num,而不是全局变量num

(3)函数模板中定义声明的对象或类型不能与模板参数同名。例如:

(4)模板参数名在同一模板参数表中只能使用一次,但可在多个函数模板声明或 定义之间重复使用。例如:

(5)模板的定义和多处声明所使用的模板参数名不一定要必须相同。例如:

(6)函数模板如果有多个模板参数,则每个模板类型前都必须使用关键字typename 或class修饰。例如:

1.3 类模板

使一个类支持模板编程,可以使一个类支持通用数据类型。

除了函数模板外,C++中还支持类模板。类模板是对成员数据类型不同的类的抽象,它说明了类的定义规则,一个类模板可以生成多种具体的类。与函数模板的定义形式类似, 类模板也是使用template关键字和尖括号“<>”中的模板形参进行说明,类的定义形式与普通类相同。

类模板并不能直接使用,需要对其进行实例化,实例化的方法是:

类名<具体类型> 对象名

类与类模板的关系:

由于类模板包含类型参数,因此也称为参数化类,如果说类是对象的抽象,对象是类的实例,则类模板是类的抽象,类是类模板的实例

用法注意:

  1. 使用类模板创建对象时,必须指明具体的数据类型。

如 A<int> a; //类A中凡是用到模板形参的地方都会被int类型所代替

  1. 当类模板有两个模板形参时,创建对象时,类型之间要用逗号分隔开。

 

类模板实例1:

构造函数直接在类内实现

#include <iostream>

using namespace std;

template<class T>

class Test
{
private:
    T val;

public:
    Test(T val):val(val){}


    T get_val()const
    {
        return val;
    }

    T set_val(const T& val)
    {
        this->val = val;
    }

};


int main()
{
    cout << "Hello World!" << endl;

    Test<int> t1(20);
    cout << t1.get_val() << endl;
    t1.set_val(30);
    cout << t1.get_val() << endl;

    Test<double> t2(2.2);
    cout << t2.get_val() << endl;
    t2.set_val(3.3);
    cout << t2.get_val() << endl;

    return 0;
}

类模板实例2:

构造函数在类内声明,类外实现。此时,类外实现的构造函数时候,都必须在函数前加上类模板标志 template<class T>  。

#include <iostream>

using namespace std;

template<class T>       // 可以是class 也可以是typename
T add(T a, T b)
{
    return a+b;
}


template<class T>
class Test
{
private:
    T val;
public:
    Test(T val);
    T get_val()const;
    void set_val(const T& val);
};

template<class T>
Test<T>::Test(T val):val(val)
{

}

template<class T>
T Test<T>::get_val()const
{
   return val;
}

template<class T>
void Test<T>::set_val(const T& val)
{
    this->val = val;
}

int main()
{
    Test<int> t1(20);
    cout << t1.get_val() << endl;
    t1.set_val(23);
    cout << t1.get_val() << endl;

    Test<double> t2(2.2);
    cout << t2.get_val() << endl;
    t2.set_val(2.32);
    cout << t2.get_val() << endl;

    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值