Loading

C++模板

C++模板

C++是一个面向对象编程的语言,提供了类的继承和组合机制,虽然在层次结构上很简单,但使用起来非常糟糕。C++使用关键字template,告诉编译器声明的类或者对象是一个模板。模板不是像继承和组合那样重用目标代码,而是重用源代码。容器不再包含名为 Object 的泛型基类,而是包含未指定的参数。与C语言中的宏定义有点类似,编译器可以将参数替换所需要的类型,使用模板比使用宏更加清晰和简单。

参考:Thinking in C++, Chapter 16

函数模板

函数模板,顾名思义就是一个模板,用于指定实现函数参数的不同类型的一种模板。语法:template <typename/class T> void func(T&)

template <typename T>
void func(T&); //声明

template <typename T> //定义
void func(T& t)
{
	....
}

int main()
{
	...
	int a = 5;
	func(a);
	...
}

类模板

类模板就是将模板用于类,举个Stack类的例子,首先在stack.h中声明一个类模板,注意由于模板不是函数,不能单独编译。模板必须与特定的模板实例化请求一起使用。因此,最简单的方式就是将所有模板信息放在一个头文件中,并在要使用该模板的文件中包含该头文件。在stack类这个例子中就只有stack.h,而没有stack.cpp文件
定义和使用类模板

template <typename T>	//声明
class Stack
{
private:
	T *base;
	...
public:
	Stack();
}

//定义类模板中的函数,Stack::Stack改为Stack<T>::Stack
template <typename T>
Stack<T>::Stack()
{
	...
}

//调用该模板
int main()
{
	...
	Stack<int> s;	//需要加<int>
	...
}

stack.h:

//stack.h
#ifndef _STACK_H
#define _STACK_H

const int size = 128;

//类模板
template <typename T>   //C++11,用typename T代替class T
class Stack
{
private:
    int top;
    T *base;  //栈底指针
    int size;   //栈中元素个数
public:
    Stack(int size);
    bool push(T e);
    bool pop(T& e);
    void peek();
    bool isEmpty();
    void show();    //展示栈中所有元素
};

template <typename T>
Stack<T>::Stack(int size)
{
    this->base = new T[size]; //dynamic memory allocation
    //new如果分配内存失败则会抛出异常
    this->top = 0;  //指向栈顶的元素的下一个位置
    this->size = size;
}

//栈满没有考虑扩容的问题
template <typename T>
bool Stack<T>::push(T e)
{
    if(this->top >= this->size)
        return false;   //栈满
    this->base[top++] = e;    //入栈,栈顶指针+1
    return true;
}

template <typename T>
bool Stack<T>::pop(T& e)
{
    if(this->top == 0)  //栈空
        return false;
    e = this->base[--top];    //通过e传递出去
    return true;
}

//0 1 2 3
template <typename T>
bool Stack<T>::isEmpty()
{
    return (this->top == 0);   
}
#endif

main.cpp:

#include <iostream>
#include "stack.h"

struct customer
{
    char fullname[35];
    double payment;
};

int main()
{
    using namespace std;
    Stack<customer> s(128); //栈大小:128个customer
    customer c1 = {"c1", 23.5};
    customer c2 = {"c2", 39.3};
    customer c3 = {"c3", 14.7};
    customer c4;    //接收出栈的元素

    //元素入栈
    if(s.push(c1)) cout << "c1入栈..\n";
    s.push(c2);
    s.push(c3);
    if(s.pop(c4)) cout << "c4出栈..\n";
    cout << "pop(c4): " << c4.fullname << ", " << c4.payment << endl;


    return 0;
}

参考资料:C++ Primer Plus(第六版) p569

模板重载

模板语法:template <typename/class T> void func(T &, T &);

其中typename和class都可以表示类或者原始类型(int、double、char等),后面是函数函数返回类型void,函数名func,参数类型为T&,编译器会将T&转为所需要的类型,如int&、double&。

#include <iostream>

using namespace std;

/****************************/
//template overloading

template <typename T>
void Swap(T &a, T &b);

template <typename T>
void Swap(T *a, T *b, int);

/****************************/

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

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

    string s("abc");
    string t("def");
    Swap(s, t);
    cout << s << endl;
    cout << t << endl;

    const int n = 3;
    int e[n] = {1,2,3};
    int f[n] = {4,5,6};

    cout << "before swap:" << endl;
    for(int i = 0; i < n; i++)
        cout << e[i] << " ";
    cout << endl;
    for(int i = 0; i < n; i++)
        cout << f[i] << " ";
    Swap(e, f, n);
    cout << endl;
    
    cout << "after swap:" << endl;
    for(int i = 0; i < n; i++)
        cout << e[i] << " ";
    cout << endl;
    for(int i = 0; i < n; i++)
        cout << f[i] << " ";
    
    return 0;
}

//template overloading definition
template <class T>
void Swap(T &a, T &b){
    T temp;
    temp = a;
    a = b;
    b = temp;
}

//template overloading definition
template <class T>
void Swap(T *a, T *b, int n){
    for(int i = 0; i < n; i++){
        T temp;
        temp = a[i];
        a[i] = b[i];
        b[i] = temp;
    }
}

输出如下:

显式实例化和显式具体化

显式实例化(explicit instantiation),显式具体化(explicit specialization)。

显式实例化对应的是隐式实例化,上面的列子Swap(a, b)就是利用Swap的模板生成一个int类型的实例,即隐式实例化。

显式实例化语法:template void Swap<double>(double &, double &);

显示具体化语法:

template <> void Swap(double &, double &); 或者template<> void Swap<double>(double &, double &);

并且声明了显式具体化还需要对其进行定义,有了显式具体化告诉编译器不要使用Swap的原始模板来生成一个参数类型为double型Swap实例。

C++ Primer Plus书中写到:

#include <iostream>
#include <string>

using namespace std;

template <typename T>
void Swap(T &a, T &b);

template <typename T>
void Swap(T *a, T *b, int);

template <> void Swap<int>(int &, int &);   //explicit specialization,必须定义
template void Swap<double>(double &, double &);  //explicit instantiation


int main()
{
    double a = 3.4, b = 5.6;
    Swap(a, b);
    return 0;
}

//orginal template
template <class T>
void Swap(T &a, T &b){
    T temp;
    temp = a;
    a = b;
    b = temp;
}


//显示具体化 (explicit specialization)
template <> void Swap<int>(int &a, int &b){
    int temp;
    temp = a;
    a = b;
    b = temp;
}
posted @ 2024-05-05 13:57  记录学习的Lyx  阅读(140)  评论(0编辑  收藏  举报