第22节 类模板 – 下

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/pt_raspi_fresher/article/details/88606430

-------------------------------------资源来源于网络,仅供自学使用,如有侵权,联系我必删.

第一:

类模板的局部特化

? 类模板可以定义多个类型参数

#include <cstdlib>
#include <iostream>

using namespace std;

//类模板可以定义多个类型参数
template<typename T1, typename T2>//T1和T2二个泛型参数的类模板
class Test//类模板主体
{
public:
    void add(T1 a, T2 b)
    {
        cout<<(a + b)<<endl;
    }
};

int main(int argc, char *argv[])
{
    Test<double, int> t;//T1是double  T2是int
    
    t.add(10.0001, 8);
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

? 类模板可以被局部特化
― 可以指定类模板的特定实现 , 并要求某些类型参数仍然必须得模板的用户指定

#include <cstdlib>
#include <iostream>

using namespace std;

template<typename T1, typename T2>
class Test
{
public:
    void add(T1 a, T2 b)
    {
        cout<<(a + b)<<endl;
    }
};

/*
template<typename T>
class Test<T, T>
{
public:
    void add(T a, T b)
    {
        cout<<"add(T a, T b)"<<endl;
        cout<<static_cast<T>(a + b)<<endl;//强制类型转换
    }
};
*/

template<typename T>
class Test<T, int>//固定第二个参数为int
{
public:
    void add(T a, int b)
    {
        cout<<"add(T a, int b)"<<endl;
        cout<<a + b<<endl;
    }
};

template<typename T1, typename T2>
class Test<T1*, T2*>//二个指针
{
public:
    void add(T1* a, T2* b)
    {
        cout<<"add(T1* a, T2* b)"<<endl;
    }
};

int main(int argc, char *argv[])
{
    int i = 0;
    int j = 0;
    
    //下面函数有局部特化则会优先选择有局部特化的类模板
    Test<double, int> t; // <T, int>
    Test<long, long> ti; // <T1, T2>
    Test<float, int> tt; // <T, int>
    Test<int*, int*> tp; // <T*, T*>
    
    t.add(10.0001, 8);
    ti.add(2, 3);
    tt.add(4, 5);
    tp.add(&i, &j);
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

第二:

思考

为什么需要特化 , 而不重新定义新类 ?

―  特化和重新定义新类看上去没有本质区别 , 但是如果定义新类 , 那么将变成一个类模板和一个新类 ,使用的时候需要考虑究竟是用类模板还是用新类
―  而特化可以统一的方式使用类模板和特化类 , 编译器自动优先选择特化类

第三:

 函数模板和类模板的模板参数可以是普通数值

#include <cstdlib>
#include <iostream>

using namespace std;

template<typename T, int N>
void func()
{
    T array[N] = {0};//动态指定局部数组的大小N
    
    for(int i = 0; i < N; i++)
    {
        array[i] = i + 1;
        
        cout<<array[i]<<" ";
    }
    
    cout<<endl;
}

int main(int argc, char *argv[])
{
    //函数模板和类模板的模板参数可以是普通数值,变量不能作为模板参数
    func<int, 5>();
    func<float, 10>();
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

第四:

非类型模板参数与特化

从1加到100的值

#include <cstdlib>
#include <iostream>

using namespace std;

template<int N>
class Sum
{
public:
    static const int VALUE = Sum<N - 1>::VALUE + N;//递归 加到N-1
};

template<>//特化类
class Sum<1>
{
public:
    static const int VALUE = 1;
};

int main(int argc, char *argv[])
{
    cout<<Sum<10>::VALUE<<endl;//编译器用递归计算
    cout<<Sum<100>::VALUE<<endl;
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

? 非类型模板参数的限制
    ? 变量不能作为模板参数
    ? 浮点数类对象不能作为模板参数
    ? 全局指针不能作为模板参数
编译器的推导过程是在编译阶段完成的 。 因此 ,编译器的推导必须依赖于特化类 , 否则推导过程无法结束 。

第五:

工程问题

在实际工程中内存操作是 bug 的重要来源

C++ 将堆内存交由程序员自由使用 , 因此
   ? 未及时释放 , 将产生内存泄漏
   ? 重复释放同一段内存 , 行为未知
   ? 使用越界 , 操作了不属于自己的内存

思考

怎样最大限度的避开上述的使用问题 ?

工程问题

? 内存越界的问题常发生于数组的使用中
― 解决方案 : 数组类
― 工程中 , 在非特殊情况下 , 要求开发者使用预先编写的数组类对象代替  C 语言中的原生数组

工程问题
?  内存泄漏内存多次释放常发生于指针的使用过程中
― 解决方案 : 智能指针
― 工程中 , 要求开发者使用预先编写的智能指针类对象代替C语言中的原生指针

第六:

智能指针
  工程中的智能指针是一个类模板
― 通过构造函数接管申请的堆内存
― 通过析构函数确保堆内存被及时释放
― 通过重载指针运算符  *  和   - >  模拟指针的行为
― 通过重载比较运算符  ==  和   !=  模拟指针的比较

智能指针的创建与使用

//SmartPointer.h
#ifndef _SMARTPOINTER_H_
#define _SMARTPOINTER_H_

template<typename T>
class SmartPointer
{
protected:
    T* m_pointer;//成员变量 指针
public:
    //定义无参构造函数
    SmartPointer();
    //通过构造函数接管申请的堆内存
    SmartPointer(const T* pointer);
    //通过析构函数确保堆内存被及时释放
    ~SmartPointer();
    //通过重载指针运算符  *  的行为
    T* operator->();
    //通过重载指针运算符  - >  模拟指针
    T& operator*();
};

#endif
//SmartPointer.hpp
#ifndef _SMARTPOINTER_DEF_H_
#define _SMARTPOINTER_DEF_H_

#include "SmartPointer.h"

template<typename T>//类模板,泛型类型T
SmartPointer<T>::SmartPointer()
{
    m_pointer = NULL;
}

template<typename T>
SmartPointer<T>::SmartPointer(const T* pointer)
{
    m_pointer = const_cast<T*>(pointer);
}

template<typename T>
SmartPointer<T>::~SmartPointer()//析构函数
{
    delete m_pointer;
}

template<typename T>
T* SmartPointer<T>::operator->()//重载运算符 ->
{
    return m_pointer;
}

template<typename T>
T& SmartPointer<T>::operator*()//重载运算符 *
{
    return *m_pointer;    
}    

#endif
#include <cstdlib>
#include <iostream>
#include "SmartPointer.hpp"

using namespace std;

class Test
{
public:
    int i;
    void print()
    {
        cout<<i<<endl;
    }
};

int main(int argc, char *argv[])
{
    SmartPointer<int> pi = new int(5);//指向整型的指针,pi是指针
    SmartPointer<Test> pt = new Test();//pt掌管堆空间的对象
    
    cout<<*pi<<endl;//打印5
    
    *pi = 10;
    
    cout<<*pi<<endl;//打印10
    
    pt->i = 20;
    pt->print();//pt是一个智能指针
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

小结

?  类模板中可以有一个 或多个未指定的泛指类型
?  可以在需要的特化类模板
?  特化可以统一的方式使用类模板和新定义的类
?  特化类总是被编译器优先选择使用
?  模板的参数可以是普通数值
?  数组类和智能指针可以最大限度的避免内存相关的bug

猜你喜欢

转载自blog.csdn.net/pt_raspi_fresher/article/details/88606430