從零開始學C++之對象的使用(三):static 與單例模式、auto_ptr與單例模式、const 用法小結、mutable修飾符

來源:互聯網
上載者:User

一、static 與單例模式

單例模式也就是簡單的一種設計模式,它需要:

保證一個類只有一個執行個體,並提供一個全域訪問點

禁止拷貝

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#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);
    Singleton &operator=(const Singleton &other);
    Singleton()
    {
        cout << "Singleton ..." << endl;
    }
    static Singleton *instance_;
};

Singleton *Singleton::instance_;

int main(void)
{
    //Singleton s1;
    //Singleton s2;

    Singleton *s1 = Singleton::GetInstance();
    Singleton *s2 = Singleton::GetInstance();

    //Singleton s3(*s1);        // 調用拷貝建構函式

    return 0;
}


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


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

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include <iostream>
using namespace std;

class Singleton
{
public:
    static Singleton *GetInstance()
    {
        if (instacne_ == NULL)
        {
            instacne_ = new Singleton;
        }
        return instacne_;
    }

    ~Singleton()
    {
        cout << "~Singleton ..." << endl;
    }

    //static void Free()
    //{
    //  if (instacne_ != NULL)
    //  {
    //      delete instacne_;
    //  }
    //}

    class Garbo
    {
    public:
        ~Garbo()
        {
            if (Singleton::instacne_ != NULL)
            {
                delete instacne_;
            }
        }
    };
private:
    Singleton(const Singleton &other);
    Singleton &operator=(const Singleton &other);
    Singleton()
    {
        cout << "Singleton ..." << endl;
    }
    static Singleton *instacne_;

    static Garbo garbo_;    // 利用對象的確定性析構
};

Singleton::Garbo Singleton::garbo_;
Singleton *Singleton::instacne_;

int main(void)
{
    //Singleton s1;
    //Singleton s2;

    Singleton *s1 = Singleton::GetInstance();
    Singleton *s2 = Singleton::GetInstance();

    //Singleton s3(*s1);        // 調用拷貝建構函式

    return 0;
}

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


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

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#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);
    Singleton &operator=(const Singleton &other);
    Singleton()
    {
        cout << "Singleton ..." << endl;
    }
};

int main(void)
{
    Singleton &s1 = Singleton::GetInstance();
    Singleton &s2 = Singleton::GetInstance();

    return 0;
}

局部靜態對象只會初始化一次,所以調用多次GetInstance函數得到的是同一個對象。由於函數內使用了靜態對象,故不是安全執行緒的。實際上也可以使用auto_ptr 智能指標 來解決,程式如下,更詳細的對auto_ptr 的討論參見這裡。


 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#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 s2;

    Singleton *s1 = Singleton::GetInstance();
    Singleton *s2 = Singleton::GetInstance();

    //Singleton s3(*s1);        // 調用拷貝建構函式

    return 0;
}

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

(一)、const 成員函數

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

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

(二)、const 對象

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

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

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


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


 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <iostream>
using namespace std;

class Test
{
public:
    Test(int x) : x_(x), outputTimes_(0)
    {

    }
    int GetX() const
    {
        cout << "const GetX ..." << endl;
        //x_ = 100;
        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_;
};

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 用法總結

可以對const 的用法做個小總結:



參考:

C++ primer 第四版
Effective C++ 3rd
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.