C++ Primer 學習筆記_24_類與資料抽象(10)--static 與單例模式、auto_ptr與單例模式、const成員函數、const 對象、mutable修飾符,constmutable

來源:互聯網
上載者:User

C++ Primer 學習筆記_24_類與資料抽象(10)--static 與單例模式、auto_ptr與單例模式、const成員函數、const 對象、mutable修飾符,constmutable

C++ Primer 學習筆記_24_類與資料抽象(10)--static 與單例模式、auto_ptr與單例模式、const成員函數、const 對象、mutable修飾符

前言

【例】寫出物件導向的五個基本原則?

解答:單一職責原則,開放封閉原則,依賴倒置原則,介面隔離原則和裡氏替換原則

裡氏替換原則:子類型必須能夠替換他們的基底類型。

    設計模式分為三種類型:建立型模式、結構型模式和行為型模式


一、static 與單例模式

1、單例模式
單例模式的意圖:保證一個類僅有一個執行個體,並提供一個訪問它的全域訪問點。
(1)第一種形式
#include <iostream>#include <string>using namespace std;class Singleton{private:    static Singleton s;    int i;    Singleton(int x): i(x) {cout << "Singleton" << endl;}    Singleton & operator = (Singleton&); //不允許賦值    Singleton(const Singleton&); //不允許拷貝public:    static Singleton& instance() {return s;}    int getValue() {return i;}    void setValue(int x) {i = x;}};Singleton Singleton::s(47); //定義靜態成員sint main(){    Singleton& s = Singleton::instance();    cout << s.getValue() << endl;    Singleton& s2 = Singleton::instance();    s2.setValue(9);    cout << s.getValue() << endl;    return 0;}
運行結果:
Singleton
47
9
    上述實現通過返回一個引用實現單列模式。如果返回的是一個指標而不是引用,使用者可能會不小心刪除此指標,因此上述實現比返回指標更安全。

(2)第二種形式
#include <iostream>#include <string>using namespace std;class Singleton{private:    int i;    Singleton(int x): i(x) {cout << "Singleton" << endl;}    void operator=(Singleton&);    Singleton(const Singleton&); //不允許拷貝public:    static Singleton& instance()    {        static Singleton s(47);        return s;    }    int getValue() {return i;}    void setValue(int x) {i = x;}};int main(){    Singleton& s = Singleton::instance();    cout << s.getValue() << endl;    Singleton& s2 = Singleton::instance();    s2.setValue(9);    cout << s.getValue() << endl;    return 0;}
運行結果:
Singleton
47
9
    上述方法時通過成員函數內部的靜態對象的建立實現單例模式。
    注意上述兩種方法並未考慮安全執行緒的問題,如需應用在多線程環境下,需要加鎖。

【例子:禁止拷貝,賦值,預設建構函式建立對象操作】
#include <iostream>using namespace std;class Singleton{public:    static Singleton *GetInstance()    {        if (instance_ == NULL)        {            instance_ = new Singleton;        }        return instance_;    }    ~Singleton()    {        cout << "~Singleton ..." << endl;    }private:    Singleton(const Singleton &other);  //將拷貝函數放在private,禁止拷貝    Singleton &operator=(const Singleton &other);  //禁止賦值    Singleton()  //禁止建立對象    {        cout << "Singleton ..." << endl;    }    static Singleton *instance_;};Singleton *Singleton::instance_;int main(void){    //Singleton s1;  // Error,調用預設建構函式    Singleton *s1 = Singleton::GetInstance();    Singleton *s2 = Singleton::GetInstance();    //Singleton s3(*s1);        // Error,調用拷貝建構函式    return 0;}
運行結果:Singleton ...


    上述程式雖然調用了兩個GetInstance函數,但只調用一次建構函式,即建立一個對象。將賦值運算子和拷貝建構函式聲明為私人,禁止拷貝。但程式存在一個問題就是物件存留期到時不會被析構。


2、為瞭解決對象不會被析構的問題,可以使用一個靜態嵌套類對象來解決:

#include <iostream>using namespace std;class Singleton{public:    static Singleton *GetInstance()    {        if (instance_ == NULL)        {            instance_ = new Singleton;        }        return instance_;    }    ~Singleton()    {        cout << "~Singleton ..." << endl;    }    class Garbo    {    public:        ~Garbo()        {            if (Singleton::instance_ != NULL)            {                delete instance_;            }        }    };private:    Singleton(const Singleton &other);  //將拷貝函數放在private,禁止拷貝    Singleton &operator=(const Singleton &other);  //禁止賦值    Singleton()  //禁止建立對象    {        cout << "Singleton ..." << endl;    }    static Singleton* instance_;    static Garbo garbo_;    // 利用對象的確定性析構};Singleton::Garbo Singleton::garbo_;Singleton* Singleton::instance_;int main(void){    //Singleton s1;  // Error,調用預設建構函式    Singleton *s1 = Singleton::GetInstance();    Singleton *s2 = Singleton::GetInstance();    //Singleton s3(*s1);        // Error,調用拷貝建構函式    return 0;}
運行結果:Singleton ...
~Singleton ...

解釋:利用靜態嵌套對象的確定性析構會調用Garbo類的解構函式,在解構函式內delete 單例類的指標。


3、上面辦法比較繁瑣,也可以返回局部靜態對象的引用來解決:

#include <iostream>using namespace std;class Singleton{public:    static Singleton& GetInstance()    {        static Singleton instance;      // 局部靜態對象        return instance;    }    ~Singleton()    {        cout << "~Singleton ..." << endl;    }private:    Singleton(const Singleton &other);  //將拷貝函數放在private,禁止拷貝    Singleton &operator=(const Singleton &other);  //禁止賦值    Singleton()  //禁止建立對象    {        cout << "Singleton ..." << endl;    }};int main(void){    Singleton& s1 = Singleton::GetInstance();    Singleton& s2 = Singleton::GetInstance();    return 0;}
運行結果:Singleton ...
~Singleton ...

解釋:局部靜態對象只會初始化一次,所以調用多次GetInstance函數得到的是同一個對象。由於函數內使用了靜態對象,故不是安全執行緒的。


4、實際上也可以使用auto_ptr 智能指標來解決,程式如下,更詳細的對auto_ptr將在後續討論。

#include <iostream>#include<memory>using namespace std;class Singleton{public:    static Singleton *GetInstance()    {        if (instance_.get() == NULL)        {            instance_ = auto_ptr<Singleton>(new Singleton);        }        return instance_.get();    }    ~Singleton()    {        cout << "~Singleton ..." << endl;    }private:    Singleton(const Singleton &other);    Singleton &operator=(const Singleton &other);    Singleton()    {        cout << "Singleton ..." << endl;    }    static auto_ptr<Singleton> instance_;};auto_ptr<Singleton> Singleton::instance_;int main(void){    Singleton *s1 = Singleton::GetInstance();    Singleton *s2 = Singleton::GetInstance();    return 0;}
運行結果:
Singleton ...
~Singleton ...

5、餓漢式單例模式(在類載入時就完成了初始化,所以類載入較慢,但擷取對象的速度快)

    實際上,上述所有的單例模式例子都不是安全執行緒的,設想如果兩個線程同時運行到語句if (instance == null),而此時該執行個體的確沒有建立,那麼兩個線程都會建立一個執行個體。如果不希望加鎖實現安全執行緒,可以使用餓漢模式(即在main函數之前先產生一個執行個體):

#include <iostream>using namespace std;class Singleton{public:    static const Singleton* GetInstance()    {        return instance_;    }    ~Singleton()    {        cout << "~Singleton ..." << endl;    }    class Garbo    {    public:        ~Garbo()        {            if (Singleton::instance_ != NULL)            {                delete instance_;            }        }    };private:    Singleton(const Singleton &other);  //將拷貝函數放在private,禁止拷貝    Singleton &operator=(const Singleton &other);  //禁止賦值    Singleton()  //禁止建立對象    {        cout << "Singleton ..." << endl;    }    static const Singleton* instance_;    static Garbo garbo_;    // 利用對象的確定性析構};const Singleton* Singleton::instance_ = new Singleton();Singleton::Garbo Singleton::garbo_;int main(void){    //Singleton s1;  // Error,調用預設建構函式    const Singleton *s1 = Singleton::GetInstance();    const Singleton *s2 = Singleton::GetInstance();    //Singleton s3(*s1);        // Error,調用拷貝建構函式    return 0;}

運行結果:
Singleton ...
~Singleton ...


6、或者通過加鎖方式實現,詳細將在後續討論。


二、const成員函數、const 對象、mutable修飾符

1、const 成員函數

    const成員函數不會修改對象的狀態

    const成員函數只能訪問資料成員的值,而不能修改它


2、const 對象

如果把一個對象指定為const,就是告訴編譯器不要修改它
const對象的定義:

const 類名 對象名(參數表);

const對象不能調用非const成員函數


3、mutable修飾

用mutable修飾的資料成員即使在const對象或在const成員函數中都可以被修改。

#include <iostream>using namespace std;class Test{public:    Test(int x) : x_(x), outputTimes_(0) { }        int GetX() const    {        cout << "const GetX ..." << endl;        //x_ = 100;  //Error,嘗試修改資料成員            return x_;    }    int GetX()    {        cout << "GetX ..." << endl;        return x_;    }    void Output() const    {        cout << "x=" << x_ << endl;        outputTimes_++;    }    int GetOutputTimes() const    {        return outputTimes_;    }private:    int x_;    mutable int outputTimes_;  //mutable修飾};int main(void){    const Test t(10);    t.GetX();    Test t2(20);    t2.GetX();    t.Output();    t.Output();    cout << t.GetOutputTimes() << endl;    return 0;}
運行結果:

const GetX ...
GetX ...
x=10
x=10
2



參考:

C++ primer 第四版
Effective C++ 3rd

http://blog.csdn.net/jnu_simba/article/details/9282235

http://blog.csdn.net/zjf280441589/article/details/24704603

C++編程規範

著作權聲明:本文為博主原創文章,未經博主允許不得轉載。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.