zoukankan      html  css  js  c++  java
  • C++--第22课

    第22课 - 类模板 - 下

    1. 类模板的局部特化

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

    #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;

        }

    };

    int main(int argc, char *argv[])

    {

        Test<double, int> t;

        t.add(10.0001, 8);

        cout << "Press the enter key to continue ...";

        cin.get();

        return EXIT_SUCCESS;

    }

    运行结果:

    18.0001

    类模板可以被局部特化

    可以指定类模板的特定实现,并要求某些类型参数仍然必须的模板的用户指定。

    #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>

    {

    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;

    }

    运行结果:

    add(T a, int b)

    18.0001

    5

    add(T a, int b)

    9

    add(T1* a, T2* b)

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

    特化和重新定义新类看上去没有本质的区别,但是如果定义新类,那么将变成一个类模板和一个新类,使用的时候需要考虑究竟是用类模板还是用新类。

    而特化可以统一的方式使用类模板和特化类,编译器自动优先选择特化类。

    2. 非类型模板参数

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

    #include <cstdlib>

    #include <iostream>

    using namespace std;

    template<typename T, int N> //可以对动态的数组指定大小

    void func()

    {

        T array[N] = {0};

        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 2 3 4 5

    1 2 3 4 5 6 7 8 9 10

    3. 非类型模板参数与特化

    #include <cstdlib>

    #include <iostream>

    using namespace std;

    template<int N>

    class Sum

    {

    public:

        static const int VALUE = Sum<N - 1>::VALUE + N;//VALUE在符号表中,不分配空间

    };

    //这里用到了递归的思想 ,为了有一个递归的出口,我们需要一个特化。

    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;

    }

    运行结果:

    55

    5050

    非类型模板参数得限制       

    变量不能作为模板参数。

    浮点数和类对象不能作为模板参数。(现代的编译器这不是问题)

    全局指针不能作为模板参数。

    编译器的推导过程是在编译阶段完成的。因此,编译器的推导必须依赖于特化类,否则推导过程无法实现。

    4. 工程问题

    在实际工程中内存操作是bug的重要来源。C++将堆内存交由程序员自由使用,因此:未及时释放,将产生内存泄漏;重复释放同一段内存,行为未知;使用越界,操作而不属于自己的内存。

    思考:怎么最大限度的避开上述的使用问题?

    内存越界的问题常发生于数组的使用中

    解决方案:数组类

    工程中,在非特殊情况下,要求开发者使用预先编写的数组类对象代替C语言中的原生数组。

    内存泄漏和内存多次释放常发生于指针的使用过程中

    解决方案:智能指针

    工程中,要求开发者使用虚线编写的智能指针类对象代替C语言中的原生指针。

    5. 智能指针

    工程中的智能指针是一个类模板:

    通过构造函数接管申请的内存;

    通过析构函数确保堆内存被及时释放;

    通过重载指针运算符*和->模拟指针的行为;

    通过重载比较运算符==和!=模拟指针的比较。

    6. 智能指针的创建于使用

    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>

    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

    main.cpp

    #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); /*即使没有delete函数也没关系,因为会自动调用析构函数,释放堆内存。*/

        SmartPointer<Test> pt = new Test();

        cout<<*pi<<endl;

        *pi = 10;

        cout<<*pi<<endl;

        pt->i = 20;

        pt->print();

        cout << "Press the enter key to continue ...";

        cin.get();

        return EXIT_SUCCESS;

    }

    运行结果:

    5

    10

    20

    小结:

    类模板中可以有一个或多个未指定的泛指类型。

    可以在需要的特化类模板。

    特化可以统一的方式使用类模板和新定义的类。

    特化类总是被编译器优先选择使用。

    模板的参数可以是普通数值。

    数组类和智能指针可以最大限度的避免内存相关的bug。

  • 相关阅读:
    查看端口被占用
    Eclipse导入包
    Eclipse中构造方法自动生成
    Eclipse中get/set方法自动生成
    Eclipse改字体大小
    设计六原则
    类的关系
    JAVA实现多线程下载
    try...catch的前世今生
    447. 回旋镖的数量
  • 原文地址:https://www.cnblogs.com/free-1122/p/11336286.html
Copyright © 2011-2022 走看看