C++模板与泛型编程

泛型编程

泛型编程:是编写出不局限于特定数据类型的、通用的算法模型的代码。

#include <iostream>

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

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

int main() {
    int a = add(2,4);
    double b = add(1.2,3.3);
    std::cout << a << std::endl;
    std::cout << b << std::endl;

    return 0;
}

向上面两个add函数,只是数据类型不同,函数的内容完全一样。如果每一种类型写一个这样的函数,int,float,unsinged int,double等这些都写一个函数。
弊端:
1.加大程序的大小
2.程序员的工作量大大提高,重复造轮子。

模板

模板是泛型编程的基础。

函数模板

定义一个函数模板

#include <iostream>
using namespace std;
//int add(int a,int b){
//    return a + b;
//}
//
//double add(double a,double b){
//    return a + b;
//}

template<typename T>
T add(T a,T b){
    return a + b;
}

int main() {
    cout << add<int>(1,2) << endl;
    cout << add<double>(1.1,2.2) << endl;
    return 0;
}

template<模板参数列表>
1.模板参数可以用class
template<class T>
2.也可以用typename
template<typename T>

注意:函数模板定义并不会导致编译器生成相关的代码,只有调用这个函数模板时,才会生成特定的函数代码。

类模板

template<typename T>
class A{
public:
    T sub(T a,T b){            //类模板里面的函数定义:直接使用模板参数,没有啥注意的
        return a - b;
    }

    A();

private:
    int sum;
};

template<typename T>             //类模板外的函数定义:需要将template<参数列表>带上,
A<T>::A():sum(0){                 //并且类名后面需要加:<所有参数>。多个参数用逗号隔开。
    cout << "构造函数" << endl;
}


int main() {
    A<int> a;
    cout << a.sub(1,4) << endl;
    //cout << add<int>(1,2) << endl;
    return 0;
}

注意:同样,类模板实例化后,若成员函数没有被调用,该成员函数不会被实例化。

类的内置-类型成员

template<typename T>
class A{
public:
    typedef T* myPoint; //typedef定义一个内置类型成员
    A();
     
    T sub(T a,T b){            //类模板里面的函数定义:直接使用模板参数,没有啥注意的
        return a - b;
    }

    myPoint myGET();

private:
    int sum;
};

template<typename T>             //类模板外的函数定义:需要将template<参数列表>带上,
A<T>::A():sum(0){                 //并且类名后面需要加:<所有参数>。多个参数用逗号隔开。
    cout << "构造函数" << endl;
}

template<typename T>
typename A<T>::myPoint A<T>::myGET(){
    return &sum;
}

用typename的另一个作用:
用于标明类型成员。

默认模板参数

默认值参数(统一规则):从有默认值参数的位置开始,它后面的参数都必须有默认值。

类模板的默认参数使用

template<typename T = int,int a = 3>
class A{
......
}

使用的方式:
可以只写前面的一个或者多个 参数,其他用默认参数:
A <string> a;
也可以都写:
A<string,5> a;

函数模板的默认参数使用

template<typename T = double>
T add(T a,T b){
    return a + b;
}

上面修改add函数模板。

默认参数为int。
可以这样使用:
add(1,1);(即使不写默认模板参数,也可以这么做,编译器会根据实参类型自动推导出模板参数类型)

模板的显示实例化

含有模板的.h文件在多个不同的.cpp文件中被使用,因为每个.cpp文件是独立的,因此每个.obj文件中都含有一份模板。
这样会导致程序代码占用内存大。

解决办法:
1.在某个.cpp文件中定义模板:
template A<double>;
2.在其他使用该实例化模板的.cpp文件中,用extern声明
extern template A<double>;
extern 会告诉编译器这是个声明,在其他.cpp文件中已经有一个该类模板的实例化版本了。

注意:只能一处定义,可以多处声明。

缺点:使用template A<double>;实例化定义,系统会把类模板以及所有成员函数都实例化出来。
这样会增加编译的时间和代码长度。
根据优劣合理的分析使用。

模板特化

为什么需要特化?
下面由代码讲解。

全特化:模板参数全部特化。
偏特化:模板参数部分特化。

类模板全特化

#include <iostream>

using namespace std;

template<typename T,typename  U>
class Student{
public:
    Student(){
        cout << "泛型模板" << endl;
    }

    void Show(T a){
        cout << a << endl;
    }
};

template<>             //全特化,即里面的参数都特化到了类,故<>中为空
class Student<string,int>{
public:
    Student(){
        cout << "Student<string,int>特化版本"   << endl;
    }

    void show(string a){
        cout << a << endl;
    };
};

int main() {
    Student<int ,int> libai;
    libai.Show(23);
    Student<string,int> sunwukong;
    sunwukong.show("sunwukong");
    return 0;
}

运行结果:

泛型模板
23
Student<string,int>特化版本
sunwukong

类模板偏特化

1.参数数量上的偏特化
2.参数范围上的偏特化

#include <iostream>

using namespace std;

template<typename T,typename  U>
class Student{
public:
    Student(){
        cout << "泛型模板" << endl;
    }

    void Show(T a){
        cout << a << endl;
    }
};

template<>             //全特化,即里面的参数都特化到了类,故<>中为空
class Student<string,int>{
public:
    Student(){
        cout << "Student<string,int>特化版本"   << endl;
    }

    void show(string a){
        cout << a << endl;
    };
};

template<typename U>         //1.参数数量上的偏特化,只特化前面的T类型
class Student<string,U>{
public:
    Student(){
        cout << "Student<string,U>参数数量上的偏特化"   << endl;
    }

    void show(string a){
        cout << a << endl;
    };
};

template<typename T,typename  U>       //2.参数范围上的偏特化:const ,指针,引用等都是参数范围上的偏特化
class Student<const T,const U>{
public:
    Student(){
        cout << "Student<const T,const U>参数范围上的偏特化" << endl;
    }

    void Show(T a){
        cout << a << endl;
    }
};
int main() {
    Student<int ,int> libai;
    libai.Show(23);
    Student<string,int> sunwukong;
    sunwukong.show("sunwukong");
    Student<string,double> xiaohei;
    xiaohei.show("xiaohei");
    Student<const int,const int> xiaoming;
    xiaoming.Show(22);
    return 0;
}
}

运行结果:

泛型模板
23
Student<string,int>特化版本
sunwukong
Student<string,U>参数数量上的偏特化
xiaohei
Student<const T,const U>参数范围上的偏特化
22

函数模板全特化

#include <iostream>
using namespace std;

template<typename T,typename U>
void show(T a,U b){
    cout << a << endl;
    cout << b << endl;
}

template<>
void show<double,double>(double a,double b){
    cout << "double:" << a << endl;
    cout << "double:" << b << endl;
}

//template<typename U>     //error:non-class, non-variable partial specialization ‘show<double, U>’ is not allowed
//void show<double,U>(double a,U b){
//    cout << "偏:double:" << a << endl;
//    cout << "偏:double:" << b << endl;
//}

int main() {
    show<int,int>(1,2);
    show<double,double>(1.1,2.2);
    show<double,int>(1.3,2);
    return 0;
}

函数模板偏特化

函数模板不能偏特化。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值