zoukankan      html  css  js  c++  java
  • C++解析(27):数组、智能指针与单例类模板

    0.目录

    1.数组类模板

    2.智能指针类模板

    3.单例类模板

    4.小结

    1.数组类模板

    模板参数可以是数值型参数(非类型参数):

    数值型模板参数的限制:

    • 变量不能作为模板参数
    • 浮点数不能作为模板参数
    • 类对象不能作为模板参数
    • 。。。

    本质:
    模板参数是在编译阶段被处理的单元,因此,在编译阶段必须准确无误的唯一确定

    1.1 类模板高效率求和

    用你觉得最高效的方法求 1+2+3+...+N 的值!
    示例——使用模板、递归和特化求和:

    #include <iostream>
    
    using namespace std;
    
    template
    < int N >
    class Sum
    {
    public:
        static const int VALUE = Sum<N-1>::VALUE + N;
    };
    
    template
    < >
    class Sum < 1 >
    {
    public:
        static const int VALUE = 1;
    };
    
    int main()
    {
        cout << "1 + 2 + 3 + ... + 10 = " << Sum<10>::VALUE << endl;
        cout << "1 + 2 + 3 + ... + 100 = " << Sum<100>::VALUE << endl;
        
        return 0;
    }
    

    运行结果为:

    [root@bogon Desktop]# g++ test.cpp
    [root@bogon Desktop]# ./a.out 
    1 + 2 + 3 + ... + 10 = 55
    1 + 2 + 3 + ... + 100 = 5050
    

    从效率的角度来说,这里的求和是很高效的。既没有加减法,也没有乘除法,也没有函数调用,也没有循环。在输出的时候VALUE是一个常量,常量的值在编译的时候就已经确定了。因此,输出的时候就仅仅是访问一个常量的值。
    相加求和是在编译器编译程序的时候完成的,编译完程序之后要求的和就已经确定了,所以在运行的时候就可以直接访问到这个和的值了,而不需要做任何其他运算,因此效率是很高的。

    1.2 数组类模板

    示例——实现数组类模板:

    // Array.h
    #ifndef _ARRAY_H_
    #define _ARRAY_H_
    
    template
    < typename T, int N >
    class Array
    {
        T m_array[N];
    public:
        int length();
        bool set(int index, T value);
        bool get(int index, T& value);
        T& operator[] (int index);
        T operator[] (int index) const;
        virtual ~Array();
    };
    
    template
    < typename T, int N >
    int Array<T, N>::length()
    {
        return N;
    }
    
    template
    < typename T, int N >
    bool Array<T, N>::set(int index, T value)
    {
        bool ret = (0 <= index) && (index < N);
        
        if( ret )
        {
            m_array[index] = value;
        }
        
        return ret;
    }
    
    template
    < typename T, int N >
    bool Array<T, N>::get(int index, T& value)
    {
        bool ret = (0 <= index) && (index < N);
        
        if( ret )
        {
            value = m_array[index];
        }
        
        return ret;
    }
    
    template
    < typename T, int N >
    T& Array<T, N>::operator[] (int index)
    {
        return m_array[index];
    }
    
    template
    < typename T, int N >
    T Array<T, N>::operator[] (int index) const
    {
        return m_array[index];
    }
    
    template
    < typename T, int N >
    Array<T, N>::~Array()
    {
    }
    
    #endif
    
    // main.cpp
    #include <iostream>
    #include "Array.h"
    
    using namespace std;
    
    int main()
    {
        Array<double, 5> ad;
        
        for(int i=0; i<ad.length(); i++)
        {
            ad[i] = i * i;
        }
        
        for(int i=0; i<ad.length(); i++)
        {
            cout << ad[i] << endl;
        }
        
        return 0;
    }
    

    运行结果为:

    [root@bogon Desktop]# g++ main.cpp
    [root@bogon Desktop]# ./a.out 
    0
    1
    4
    9
    16
    

    1.3 堆数组类模板

    示例——实现堆数组类模板(即数组创建在堆上):

    // HeapArray.h
    #ifndef _HEAPARRAY_H_
    #define _HEAPARRAY_H_
    
    template
    < typename T >
    class HeapArray
    {
    private:
        int m_length;
        T* m_pointer;
        
        HeapArray(int len);
        HeapArray(const HeapArray<T>& obj);
        bool construct();
    public:
        static HeapArray<T>* NewInstance(int length); 
        int length();
        bool get(int index, T& value);
        bool set(int index ,T value);
        T& operator [] (int index);
        T operator [] (int index) const;
        HeapArray<T>& self();
        ~HeapArray();
    };
    
    template
    < typename T >
    HeapArray<T>::HeapArray(int len)
    {
        m_length = len;
    }
    
    template
    < typename T >
    bool HeapArray<T>::construct()
    {   
        m_pointer = new T[m_length];
        
        return m_pointer != NULL;
    }
    
    template
    < typename T >
    HeapArray<T>* HeapArray<T>::NewInstance(int length)
    {
        HeapArray<T>* ret = new HeapArray<T>(length);
        
        if( !(ret && ret->construct()) )
        {
            delete ret;
            ret = 0;
        }
        
        return ret;
    }
    
    template
    < typename T >
    int HeapArray<T>::length()
    {
        return m_length;
    }
    
    template
    < typename T >
    bool HeapArray<T>::get(int index, T& value)
    {
        bool ret = (0 <= index) && (index < length());
        
        if( ret )
        {
            value = m_pointer[index];
        }
        
        return ret;
    }
    
    template
    < typename T >
    bool HeapArray<T>::set(int index, T value)
    {
        bool ret = (0 <= index) && (index < length());
        
        if( ret )
        {
            m_pointer[index] = value;
        }
        
        return ret;
    }
    
    template
    < typename T >
    T& HeapArray<T>::operator [] (int index)
    {
        return m_pointer[index];
    }
    
    template
    < typename T >
    T HeapArray<T>::operator [] (int index) const
    {
        return m_pointer[index];
    }
    
    template
    < typename T >
    HeapArray<T>& HeapArray<T>::self()
    {
        return *this;
    }
    
    template
    < typename T >
    HeapArray<T>::~HeapArray()
    {
        delete[]m_pointer;
    }
    
    #endif
    
    // main.cpp
    #include <iostream>
    #include "HeapArray.h"
    
    using namespace std;
    
    int main()
    {
        HeapArray<char>* pai = HeapArray<char>::NewInstance(10);
        
        if( pai != NULL )
        {
            HeapArray<char>& ai = pai->self();
            
            for(int i=0; i<ai.length(); i++)
            {
                ai[i] = i + 'a';
            }
            
            for(int i=0; i<ai.length(); i++)
            {
                cout << ai[i] << endl;
            }
        }
        
        delete pai;
        
        return 0;
    }
    

    运行结果为:

    [root@bogon Desktop]# g++ main.cpp
    [root@bogon Desktop]# ./a.out 
    a
    b
    c
    d
    e
    f
    g
    h
    i
    j
    

    2.智能指针类模板

    智能指针的意义:

    • 现代C++开发库中最重要的类模板之一
    • C++中自动内存管理的主要手段
    • 能够很大程度上避开内存相关的问题

    STL中的智能指针 auto_ptr

    • 生命周期结束时,销毁指向的内存空间
    • 不能指向堆数组,只能指向堆对象(变量)
    • 一片堆空间只属于一个智能指针对象
    • 多个智能指针对象不能指向同一片堆空间

    2.1 使用智能指针

    示例——使用auto_ptr:

    #include <iostream>
    #include <memory>
    
    using namespace std;
    
    class Test
    {
        string m_name;
    public:
        Test(const char* name)
        {
            cout << "Hello, " << name << "." << endl;
            
            m_name = name;
        }
        
        void print()
        {
            cout << "I'm " << m_name << "." << endl;
        }
        
        ~Test()
        {
            cout << "Goodbye, " << m_name << "." << endl;
        }
    };
    
    int main()
    {
        auto_ptr<Test> pt(new Test("HelloWorld"));
        
        cout << "pt = " << pt.get() << endl;
        pt->print();
        cout << endl;
        
        auto_ptr<Test> pt1(pt);
        
        cout << "pt = " << pt.get() << endl;
        cout << "pt1 = " << pt1.get() << endl;
        pt1->print();
        
        return 0;
    }
    

    运行结果为:

    [root@bogon Desktop]# g++ test.cpp
    [root@bogon Desktop]# ./a.out 
    Hello, HelloWorld.
    pt = 0x18ea010
    I'm HelloWorld.
    
    pt = 0
    pt1 = 0x18ea010
    I'm HelloWorld.
    Goodbye, HelloWorld.
    

    STL中的其它智能指针:

    • shared_ptr——带有引用计数机制,支持多个指针对象指向同一片内存
    • weak_ptr——配合shared_ptr而引入的一种智能指针
    • unique_ptr——一个指针对象指向一片内存空间,不能构造拷贝和赋值

    Qt中的智能指针:

    • QPointer
      1. 当其指向的对象被销毁时,它会被自动置空
      2. 析构时不会自动销毁所指向的对象
    • QSharedPointer
      1. 引用计数型智能指针
      2. 可以被自由地拷贝和赋值
      3. 当引用计数为0时才删除指向的对象

    2.2 智能指针类模板

    示例——创建智能指针类模板:

    // SmartPointer.h
    #ifndef _SMARTPOINTER_H_
    #define _SMARTPOINTER_H_
    
    template
    < typename T >
    class SmartPointer
    {
        T* mp;
    public:
        SmartPointer(T* p = NULL)
        {
            mp = p;
        }
        
        SmartPointer(const SmartPointer<T>& obj)
        {
            mp = obj.mp;
            const_cast<SmartPointer<T>&>(obj).mp = NULL;
        }
        
        SmartPointer<T>& operator = (const SmartPointer<T>& obj)
        {
            if( this != &obj )
            {
                delete mp;
                mp = obj.mp;
                const_cast<SmartPointer<T>&>(obj).mp = NULL;
            }
            
            return *this;
        }
        
        T* operator -> ()
        {
            return mp;
        }
        
        T& operator * ()
        {
            return *mp;
        }
        
        bool isNull()
        {
            return (mp == NULL);
        }
        
        T* get()
        {
            return mp;
        }
        
        ~SmartPointer()
        {
            delete mp;
        }
    };
    
    #endif
    
    // test.cpp
    #include <iostream>
    #include "SmartPointer.h"
    
    using namespace std;
    
    class Test
    {
        string m_name;
    public:
        Test(const char* name)
        {
            cout << "Hello, " << name << "." << endl;
            
            m_name = name;
        }
        
        void print()
        {
            cout << "I'm " << m_name << "." << endl;
        }
        
        ~Test()
        {
            cout << "Goodbye, " << m_name << "." << endl;
        }
    };
    
    int main()
    {
        SmartPointer<Test> pt(new Test("HelloWorld"));
        
        cout << "pt = " << pt.get() << endl;
        pt->print();
        cout << endl;
        
        SmartPointer<Test> pt1(pt);
        
        cout << "pt = " << pt.get() << endl;
        cout << "pt1 = " << pt1.get() << endl;
        pt1->print();
        
        return 0;
    }
    

    运行结果为:

    [root@bogon Desktop]# g++ test.cpp
    [root@bogon Desktop]# ./a.out 
    Hello, HelloWorld.
    pt = 0x20a3010
    I'm HelloWorld.
    
    pt = 0
    pt1 = 0x20a3010
    I'm HelloWorld.
    Goodbye, HelloWorld.
    

    3.单例类模板

    需求的提出:
    在架构设计时,某些类在整个系统生命期中最多只能有一个对象存在Single Instance)。

    如何定义一个类,使得这个类最多只能创建一个对象?

    要控制类的对象数目,必须对外隐藏构造函数
    思路:

    • 将构造函数的访问属性设置为private
    • 定义instance并初始化为NULL
    • 当需要使用对象时,访问instance的值
      1. 空值:创建对象,并用instance标记
      2. 非空值:返回instance标记的对象

    3.1 实现单例模式

    示例——实现单例模式:

    #include <iostream>
    
    using namespace std;
    
    class SObject
    {
        static SObject* c_instance; // 标识符:当前有没有对象
        
        SObject(const SObject&);
        SObject& operator= (const SObject&);
        
        SObject() { }
    public:
        static SObject* GetInstance();
        
        void print()
        {
            cout << "this = " << this << endl;
        }
    };
    
    SObject* SObject::c_instance = NULL;
    
    SObject* SObject::GetInstance()
    {
        if( c_instance == NULL )
        {
            c_instance = new SObject();
        }
        
        return c_instance;
    }
    
    int main()
    {
        SObject* s = SObject::GetInstance();
        SObject* s1 = SObject::GetInstance();
        SObject* s2 = SObject::GetInstance();
        
        s->print();
        s1->print();
        s2->print();
        
        return 0;
    }
    

    运行结果为:

    [root@bogon Desktop]# g++ test.cpp
    [root@bogon Desktop]# ./a.out 
    this = 0x17cf010
    this = 0x17cf010
    this = 0x17cf010
    

    存在的问题——需要使用单例模式时:

    • 必须定义静态成员变量c_instance
    • 必须定义静态成员函数GetInstance()

    解决方案:
    将单例模式相关的代码抽取出来,开发单例类模板。当需要单例类时,直接使用单例类模板。

    3.2 单例类模板

    示例——创建单例类模板:

    // Singleton.h
    #ifndef _SINGLETON_H_
    #define _SINGLETON_H_
    
    template
    < typename T >
    class Singleton
    {
        static T* c_instance;
    public:
        static T* GetInstance();
    };
    
    template
    < typename T >
    T* Singleton<T>::c_instance = NULL;
    
    template
    < typename T >
    T* Singleton<T>::GetInstance()
    {
        if( c_instance == NULL )
        {
            c_instance = new T();
        }
        
        return c_instance;
    }
    
    #endif
    
    // test.cpp
    #include <iostream>
    #include "Singleton.h"
    
    using namespace std;
    
    class SObject
    {
        friend class Singleton<SObject>; // 当前类需要使用单例模式
        
        SObject(const SObject&);
        SObject& operator= (const SObject&);
        
        SObject() { }
    public:
        void print()
        {
            cout << "this = " << this << endl;
        }
    };
    
    int main()
    {
        SObject* s = Singleton<SObject>::GetInstance();
        SObject* s1 = Singleton<SObject>::GetInstance();
        SObject* s2 = Singleton<SObject>::GetInstance();
        
        s->print();
        s1->print();
        s2->print();
        
        return 0;
    }
    

    运行结果为:

    [root@bogon Desktop]# g++ test.cpp
    [root@bogon Desktop]# ./a.out 
    this = 0x1bfd010
    this = 0x1bfd010
    this = 0x1bfd010
    

    4.小结

    • 模板参数可以是数值型参数
    • 数值型模板参数必须在编译期间唯一确定
    • 数组类模板是基于数值型模板参数实现的
    • 数组类模板是简易的线性表数据结构
    • 智能指针C++中自动内存管理的主要手段
    • 智能指针在各种平台上都有不同的表现形式
    • 智能指针能够尽可能的避开内存相关的问题
    • STL和Qt中都提供了对智能指针的支持
    • 单例模式是开发中最常用的设计模式之一
    • 单例模式的应用使得一个类最多只有一个对象
    • 可以将单例模式相关的代码抽象成类模板
    • 需要使用单例模式的类直接使用单例类模板
  • 相关阅读:
    一、反射机制介绍_Class 对象获取
    六、.XPATH 技术_快速获取节点
    五、.DOM4J 方式解析 XML 数据
    四、.JDOM 解析 XML 数据
    三、SAX 方式解析 XML 数据
    二、DOM方式解析XML
    一、Schema验证XML
    三、线程同步Synchronized
    二、线程状态
    JDK8Lambda和方法的引用
  • 原文地址:https://www.cnblogs.com/PyLearn/p/10093955.html
Copyright © 2011-2022 走看看