带你了解C++中的模板泛型

99 阅读2分钟

我正在参加「掘金·启航计划」。

1. 函数模板

将功能相同、类型不同的函数(类)的类型抽象成虚拟的类型。当调用函数(类实例化对象)的时候,编译器自动讲虚拟的类型具体化,这就是函数模版(类模版)。

  • 模板关键字template
  • T只能对当前函数有效,如下代码
//普通函数
void swapAll(T &a, T &b){  
    T temp = a;  
    a = b;  
    b = temp;  
    return;  
}
//函数模板
template<typename T>  
void swapAll(T &a, T &b){  
    T temp = a;  
    a = b;  
    b = temp;  
    return;  
}
  • 函数模板和普通函数都识别,会优先选择普通函数。可以加<>强制调用函数模板。
  • 函数模板自动推导时不能对函数的参数进行自动类型转换。比如下面这段代码,函数模板识别不了,就会调用普通函数。当然也可以显式强制用模版函数swapAll<int>(10,'c');
int main() {  
    swapAll(10,'c'); //自动推出T为int类型,完成int类型交换  
    return 0;  
}

当函数模板 推导出T为数组或其他自定义类型数据时可能导致运算符不识别,比如cout << 不知道怎么输出。

函数模板具体化:

template<> void swapAll<int>(Person &a, Person &b){  
    //...
    return;  
}

函数模板会编译两次:第一次,对函数模板本身编译;第二次,函数调用处将T的类型具体化。函数模版目标:模版为了实现泛型,可以减轻编程的工作量,增强函数的重用性。

2. 类模板

类模板和函数模板类似,对当前类有效。类模版的定义:

template<class T1, class T2>  
class Data{  
private:  
    T1 a;  
    T2 b;  
public:  
    Data(){}  
    Data(T1 a, T2 b){  
        this->a = a;  
        this->b = b;  
    }  
    void showData(){  
        std::cout << a << " " << b << std::endl;  
    }  
};
  • 类模版实例化对象 不能自动推导类型。

为什么呢?就上述代码而言,如果我们直接Data ob(10,20);按理说会推出T1、T2是int类型,但是如果Data ob;这样呢,无参构造就没有参数,不能推出T1、T2是什么类型。所有类模版就不支持自动推导类型。正确的写法应该是Data<int, int> ob(10,20);

类模板成员函数在类外实现,代码如下

template<class T1, class T2>  
class Data{  
private:  
    T1 a;  
    T2 b;  
public:  
    Data(){}  
    Data(T1 a, T2 b);
    void showData();
};
template<class T1, class T2>  
Data<T1, T2>::Data(T1 a, T2 b){
    this->a = a;  
    this->b = b; 
}
template<class T1, class T2>  
void Data<T1, T2>::showData(){  
    std::cout << a << " " << b << std::endl;  
}  
  • 因为template只对当前类有效,所以在外部实现成员函数的时候也是需要重写template的。
  • 类模版建议用hpp文件,h+cpp。类模版不能做h和cpp分离。

除了上面提到的,还有函数模版做友元,普通函数做友元。