浅谈模板函数和模板类以及不使用乘除,for,while,等循环和递归来计算1+2+3+4+....+n的值

模板函数

概念:一种与类型无关的代码.
作用:复用.
下面通过一个实例来实现:

template<class T>   //类比函数参数,但是模板参数传递的是类型,也可以使用typename
T Add(T a,T b)
{
    return a + b;
}

int main()
{
    int a = 10;
    int b = 20;
    cout<<Add(a,b)<<endl;               
    //Add<int>(a,b);    //显示实例化,当add函数的参数类型不同时,就会在推演类型时出错,所以此时就用到了显示实例化,明确T的类型

    float c = 1.1223;
    float d = 2.123;
    cout<<Add(c,d)<<endl;

    return 0;
}

那么是怎么实现的呢?只要想探索底层的实现原理,有一个简便的方法就是:查看汇编.
此时,我们查看汇编:
这里写图片描述
这里写图片描述
所以:编译器在编译时,会进行模板类型的推演,然后模板函数在执行时会生成不同的函数名,进而实现函数的复用.
注意:模板函数只有在调用的时候才会进行检查.如果只写模板函数是不会检查函数体是否有错误

模板函数重载

template<class T>   //类比函数参数,但是模板参数传递的是类型
T Add(T a,T b)
{
    return a + b;
}

int Add(int a,int b)
{
    return a + b;
}
int main()
{
    int a = 10;
    int b = 20;
    Add(a,b);       //调用非模板函数   

    float c = 1.1223;
    float d = 2.123;
    Add(c,d);      //调用的是模板函数
    return 0;
}

函数名相同,且在同一作用域,所以上面两个函数构成了重载.

模板类

如果要看Vector的模板实现的代码,请戳这里
模板类与模板函数相似,在这儿,我们可以通过顺序表Vector来实现模板类.

template <class T>
class Vector
{
public:
    Vector();
    Vector(const Vector<T>& v);
    Vector<T>& operator=(const Vector<T>& v);
    void PushBack(const T& value);
    void PopBack();
    void Insert(size_t pos,const T& value);
    void Erase(size_t pos);
    size_t Size();
    size_t Capacity();
    bool Empty();
    ~Vector();
protected:
    T* _first;
    T* _finish;
    T* _endofstorage;
};

敲黑板:在模板中.类名就是上例中的Vector;类型而是Vector;而在普通的类中,类名和类型相同.
当在类外面进行实现时,与我们以往写的声明是不同的.

template<class T>
Vector<T>::Vector()    //注意作用域
    :_first(NULL)
    ,_finish(NULL)
    ,_endofstorage(NULL)
{}

template<class T>      //必须写
Vector<T>::~Vector()
{
    delete[] _first;
    _first = _finish = _endofstorage = NULL;
}

当在创建对象使用时,它的声明是:

Vector<int> v;

经常使用的数据结构还有带头双向链表.
带头双向链表代码的实现

template<class T>
struct LinkNode
{
    T data;
    LinkNode<T>* prev;
    LinkNode<T>* next;

    LinkNode(const T& value)
        :data(value)
        ,prev(NULL)
        ,next(NULL)
    {}
};
template<class T>
class LinkList
{
public:
    typedef LinkNode<T> Node;
    LinkList();
    LinkList(const LinkList<T>& l);
    LinkList<T>& operator=(const LinkList<T>& l);
    void PushFront(const T& value);
    void PopFront();
    void PushBack(const T& value);
    void PopBack();
    void Insert(Node* pos,const T& value);
    void Erase(Node* pos);
    void Clear();
    ~LinkNdoe();
    bool Empty();
protected:
    Node* head;
};

模板参数——>容器适配器

在生活中,我们笔记本电脑的充电器,也叫适配器(实现电压的转化).
同样的,在我们的程序中,也可以通过某种代码去实现其它的功能.比如:用Vector去模拟实现栈.

template<class T,class Container>
//template<class T,class Container = Vector<T> >  //缺省参数
class Stack
{
public:
    void Push(const T& value)
    {
        con.PushBack(value);
    }
    void Pop()
    {
        con.PopBack()
    }
    T& Top()
    {
        con.Front();
    }
    bool Empty()
    {
        con.Empty();
    }
protected:
    Container con;
};

int main()
{
    Stack<int,class<int> > s;
    return 0;
}

模板的模板参数

与上面的适配器的实现类比:

template<class T,template<class T> class Container >

//template<class T,template<class T> class Container = Vector<T>>
class Stack
{
public:
    void Push(const T& value)
    {
        con.PushBack(value);
    }
    void Pop()
    {
        con.PopBack()
    }
    T& Top()
    {
        con.Front();
    }
    bool Empty()
    {
        con.Empty();
    }
protected:
    Container<T> con;
};

int main()
{
    Stack<int,Vector> s;
    return 0;
}

这里写图片描述

template<class T,template<class T> class Container>
其中:template<class T>表示Container是一个模板类类型的模板参数.

非类型的类模板参数

模板类的模板参数,也可以飞类型的模板参数.
比如:

template<class T,size_t N>

利用这个可以实现静态的顺序表.
注意:double是不可以做非类型的模板参数.

非类型的函数模板参数

template<class T,int value> 
T Add(const T& a)
{
    return a + value;
}
int main()
{
    cout<<Add<int,3>(10)<<endl;
    return 0;
}

类模板的特化

使用日期类来举例学习:

template<typename T1,typename T2>   
class Date
{
public:
    Date()
    {
        cout<<"Date()"<<endl;
    }
private:
    T1 _d;
    T2 _d1;
};

template<typename T1,typename T2>
class Date<T1& ,T2&>
{
public:
    Date(T1 a,T2 b)
    {
        cout<<"Date<T1&,T2&>"<<endl;
    }
private:
    T1& _d1;
    T2& _d2;
};

template<typename T1,typename T2>
class Date<T1*,T2*>
{
public:
    Date()
    {
        cout<<"Date<T1*,T2*>"<<endl;
    }
private:
    T1* _d1;
    T2* _d2;
};

//第二个参数偏特化
template<typename T1>
class Date<T1,char>
{
public:
    Date()
    {
        cout<<"Date<T1,char>"<<endl;
    }
private:
    T1 _d1;
    char _d2;
};

//第一个参数偏特化
template<typename T2>
class Date<char,T2>
{
public:
    Date()
    {
        cout<<"Date<char,T2>"<<endl;
    }
private:
    char _d1;
    T2 _d2;
};

template<>      //全特化
class Date<int,int>
{
public:
    Date()
    {
        cout<<"Date<int,int>"<<endl;
    }
private:
    int _d1;
    int _d2;
};
int main()
{
    Date<int,int> d;
    Date<char,int> d1;
    Date<double&,double&> d2(1.11,2.22);
    Date<int*,int*> d3;
    return 0;
}

总结:当该类型的模板函数实现了时,在调用时就会调用(偏特化模板函数)实现了的对应的函数.当该函数没有实现时,就会调用模板函数.注意:当类的成员变量为引用类型时,在初始化类时对于成员变量也要初始化.(引用必须初始化)

注意:模板的全特化和半特化都是在已定义的模板的基础之上,不能单独存在.

模板的分离编译

当模板的定义在.h文件中,而声明在.c文件中,而测试函数又在另外一个文件中时,在编译时可以通过吗?

总结:模板不支持分离编译,最好的做法就是,直接在模板的定义后面进行模板的实现.
如果定义和声明不在同一个文件中,那么在执行函数时就会直接编译不通过,链接失败.因为模板函数只是在执行的时候才会去推演它的类型,才会去找实现的函数,当它们不在同一个文件时,就会因为找不到而报错.

模板总结:
优点:
1. 提高了代码的复用性,节省资源.
2. 增强代码的灵活性.
缺点:
1. 不易维护,让代码变得复杂.
2. 当模板使用错误产生错误信息时,不容易找到错误信息的根源.

下面是一道拓展思维的题:
不使用乘除,for,while,等循环和递归来计算1+2+3+4+….+n的值;
方法1:

class Add_1_to_n
{
public:
    Add_1_to_n()
    {
        ret = ret + i;
        ++i;
    }
    static int sum;
    static int i;
};
int Add_1_to_n::sum = 0;
int Add_1_to_n::i = 1;

void Test()
{
    Add_1_to_n* p = new Add_1_to_n[10];
    cout<<Add_1_to_n::sum<<endl;
    delete[] p;
}

方法2:在编译期间就已经解决问题.
缺点;当n太大时,就会因为递归的层数太深而程序崩溃,无法计算出来

tempalate<size_t N>
class Add_1_to_n
{
public:
    enum
    {
        sum = Add_1_to_n(N - 1)::sum + N;
    };
};
template<>
class Add_1_to_n<1>
{
public:
    enum
    {
    sum = 1;
    };
};
void test
{
    cout<<Add_1_to_n<10>::sum<<endl;
}

方法3:鬼畜方法(反正我是想不到~~~)
缺点:因为栈比较小,所以当N太大时,就会导致栈溢出

char arr[N][N + 1] = {0};
cout<<(sizeof(arr))>>1)<<endl;

若读者有更好的方法:请指教

猜你喜欢

转载自blog.csdn.net/yinghuhu333333/article/details/80302862