C++之模板

14 篇文章 0 订阅

模板主要应用于泛型编程,现在主要就是非常火的STL(标准模板库),对于公司项目来说利用模板的可能性不大,一般一个项目是无法达到模板这个要求的。

一、函数模板

函数模板的要求是:

1、函数名一致
2、参数个数一致
3、函数体一致
4、参数类型不同

函数模板的格式:

template<class/typename T1, class/typename T2, ...>
返回类型  函数名(参数列表){
        函数体
}

举个例子:

template<typename T>
void Swap(T &a, T &b) {
    T t = a;
    a = b;
    b = t;
}

int main() {
    int a = 5;
    int b = 3;
    cout << "a = " << a << ", b = " << b << endl;
    Swap(a, b);
    cout << "a = " << a << ", b = " << b << endl;

    double c = 5.6;
    double d = 3.2;
    cout << "c = " << c << ", d = " << d << endl;
    Swap(c, d);
    cout << "c = " << c << ", d = " << d << endl;

    string e = "aaa";
    string f = "bbb";
    cout << "e = " << e << ", f = " << f << endl;
    Swap(e, f);
    cout << "e = " << e << ", f = " << f << endl;

    system("pause");
    return 0;
}

输出结果:

这里写图片描述

利用同一个函数模板可以应用于不同的类型,上面的每一次Swap的调用其实本质都是:

    Swap(a, b);   ------>     Swap<int>(a, b);
    Swap(c, d);   ------>     Swap<double>(c, d);
    Swap(e, f);   ------>     Swap<string>(e, f);

这个过程就是从函数模板转换成模板函数的一个过程, 左边是一种函数模板的隐式实例化,右边是函数模板的显示实例化。

1、函数模板与普通函数重载

template<typename T>
T getmax(T a, T b) {
    return a > b ? a : b;
}

int getmax(int a, int b) {
    return a > b ? a : b;
}

int main(){
    cout << getmax(8,5) << endl;
    system("pause");
    return 0;
}

对于这样的代码,编译器采用完全匹配的方式调用参数为int类型的函数

int getmax(int a, int b) {
    return a > b ? a : b;
}

因为函数模板的编译需要进行两次编译:
第一次:不考虑类型编译;
第二次:匹配类型,生成可调用的二进制文件

在第一次编译的时候编译器就找到了完全匹配的函数,因为不会再进行第二次编译了。

所以当函数模板与普通函数重载时,优先调用完全匹配的普通函数。

2、函数模板与函数模板重载

template<typename T>
T* const& getmax(T* const& a, T* const& b) {
    return *a > *b ? *a : *b;
}

template<typename T>
T const& getmax(T const& a, T const& b) {
    return a > b ? a : b;
}

int main(){
    cout << getmax(5,8) << endl;
    system("pause");
    return 0;
}

这段代码会调用下面这个模板函数,

template<typename T>
T const& getmax(T const& a, T const& b) {
    return a > b ? a : b;
}

当模板函数与模板函数重载时,根据参数列表进行匹配。

二、结构体模板

template<typename T>
struct student 
{
    T num;
    string name;
    int age;
};


int main(){
    student<int> stu1 = {1239234, "郭靖", 18};
    cout << stu1.num << "   " << stu1.name << "   " << stu1.age << endl;
    student<string> stu2 = {"xuesheng2", "黄蓉", 16};
    cout << stu2.num << "   " << stu2.name << "   " << stu2.age << endl;
    system("pause");
    return 0;
}

输出结果:

这里写图片描述

三、类模板

STL中常用的就是类模板,比如vector,stack都是类模板,这里就拿stack为例:

类模板的格式:

template<typename T1, typename T2, ...>
class 类名{
    类内部实现;
};

若成员函数在类内部定义则与普通类的成员函数的定义一样, 若成员函数在类外部定义则要这样写,以下面stack的构造函数为例,在函数前不仅要加

template<typename T>

域名要写成这种形式:

MyStack<T>::函数名

自实现的Stack类模板

template<typename T>
MyStack<T>::MyStack(int s) {
    size = s;
    arr = new T[size];
    top = 0;
}
#include<iostream>
#include<string>

using namespace std;

template<typename T>
class MyStack {
public:
    MyStack(int s = 1024);
    ~MyStack();
    bool isEmpty();
    bool isFull();
    void push(T num);
    T pop();
private:
    T *arr;
    int top;
    int size;
};


template<typename T>
MyStack<T>::MyStack(int s) {
    size = s;
    arr = new T[size];
    top = 0;
}

template<typename T>
MyStack<T>::~MyStack() {
    delete[]arr;
}

template<typename T>
bool MyStack<T>::isEmpty() {
    return top == 0;
}

template<typename T>
bool MyStack<T>::isFull() {
    return top == size;
}

template<typename T>
void MyStack<T>::push(T num) {

    arr[top++] = num;
}

template<typename T>
T MyStack<T>::pop() {
    return arr[--top];
}

int main() {
    MyStack<int> ms;
    ms.push(20);
    cout << ms.pop() << endl;
    ms.push(30);
    cout << ms.pop() << endl;
    ms.push(10);
    cout << ms.pop() << endl;
    cout << "-------------------" << endl;
    MyStack<string> mstr;
    mstr.push("aaa");
    cout << mstr.pop() << endl;
    mstr.push("bbb");
    cout << mstr.pop() << endl;
    mstr.push("ccc");
    cout << mstr.pop() << endl;

    cout << "-------------------" << endl;
    MyStack<double> msdou;
    msdou.push(1.1);
    cout << msdou.pop() << endl;
    msdou.push(2.2);
    cout << msdou.pop() << endl;
    msdou.push(3.3);
    cout << msdou.pop() << endl;
    system("pause");
    return 0;
}

输出结果:

这里写图片描述

MyStack<int> ms

对于这句代码,是个从类模板转换成模板类,再生成对象的过程。

如果写类模板,最好是先用一种简单的类型写一遍,再把类型替换掉就可以了。

再粘一个自实现的vector的例子,个人认为还是蛮典型的:

#include<iostream>

using namespace std;

template<typename T>
class MyVector {
public:
    MyVector(int s = 1024) {
        arr = new T[s];
        size = 0;
    }

    MyVector(MyVector<T> &another) {
        int len = another.getSize();
        arr = new T[len];
        for (int i = 0; i < len; i++) {
            arr[i] = another.arr[i];
            size++;
        }
    }

    MyVector<T>& operator=(MyVector<T> & another) {
        if (this == &another)
            return *this;
        delete[]arr;
        int len = another.getSize();
        arr = new T[len];
        for (int i = 0; i < len; i++) {
            arr[i] = another.arr[i];
            size++;
        }
        return *this;
    }

    T& operator[](int i) {
        if (i > size){
            cerr << i << "不存在" << endl;
        }
        return arr[i];
    }

    ~MyVector() {
        delete []arr;
    }
    int getSize() {
        return size;
    }

    void push_back(T num) {
        arr[size++] = num;
    }

    T pop_back() {
        return arr[--size];
    }

    friend ostream& operator<<(ostream& os, const MyVector& mv) {
        for (int i = 0; i < mv.size; i++)
            os << mv.arr[i] << " ";
        return os;
    }

private:
    T *arr;
    int size;
};

int main() {
    MyVector<int> mv;
    for(int i = 0; i < 10; i++)
        mv.push_back(i);
    cout << mv << endl;
    cout << "------------------------" << endl;

    MyVector<double> v2;
    for (int i = 0; i < 10; i++)
        v2.push_back(i + 0.1);
    cout << v2 << endl;
    cout << "------------------------" << endl;

    MyVector<char> v3;
    char c = 'a';
    for(int i = 0; i < 10; i++){
        v3.push_back(c++);
    }
    cout << v3 << endl;
    cout << "------------------------" << endl;
    system("pause");
    return 0;
}

输出结果:

这里写图片描述

四、模板特化

template<typename T1, typename T2>
class Temp {
public:
    void func(T1 t1, T2 t2) {
        cout << "class Temp " << endl;
    }
};

//完全特化
template<>    //这里不能漏掉
class Temp<int, double> {
public:
    void func(int t1, double t2) {
        cout << "class Temp<int, double>" << endl;
    }
};

//局部特化
template<typename T>
class Temp<T, double>{
public:
    void func(T t1, double t2) {
        cout << "class Temp<T, double>" << endl;
    }
};

template<typename T>
class Temp<T, T> {
public:
    void func(T t1, T t2) {
        cout << "class Temp<T, T>" << endl;
    }
};

int main(){
    Temp<int, int> temp1;
    temp1.func(1, 2);
    Temp<int, double> temp2;
    temp2.func(1, 2.0);
    Temp<float, double> temp3;
    temp3.func(1.3, 2.5);
    Temp<char, string> temp4;
    temp4.func('a', "sfafsa");
    system("pause");
    return 0;
}

输出结果:

这里写图片描述

五、模板默认参数

1、类模板默认参数

template<typename T1 = int, typename T2 = double>
class test {
public:
    void func() {
        cout << typeid(t1).name() << "   " << typeid(t2).name() << endl;
    }
private:
    T1 t1;
    T2 t2;
};
int main(){
    test<> test1;    //虽然使用了默认参数,但是<>不能少
    test1.func();
    test<float> test2;
    test2.func();
    test<char, int> test3;
    test3.func();
    system("pause");
    return 0;
}

输出结果:

这里写图片描述

2、函数模板默认参数

template<typename T = int>
void foo(T t) {
    cout << typeid(t).name() << endl;
}

int main(){
    foo("strsqa");
    foo((float)12);
    system("pause");
    return 0;
}

输出结果:

这里写图片描述

3、类模板中的成员函数模板

template<typename T1 = int, typename T2 = double>
class test {
public:
    template<typename T = int>
    void func(T t) {
        cout << typeid(t1).name() << "   " << typeid(t2).name() << "   " << typeid(t).name() << endl;
    }
private:
    T1 t1;
    T2 t2;
};

int main(){
    test<> test1;
    test1.func(1);
    test<float> test2;
    test2.func((float)1);
    test<char, int> test3;
    test3.func((double)1);
    system("pause");
    return 0;
}

输出结果:

这里写图片描述

总结:

1、模板不是一个完整的类型,使用到类型时要用到尖括号<>。

2、结构体模板和类模板必须使用显示实例化,也就是必须加<>,函数模板可以隐式实例化。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值