亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

一篇文章帶你了解C++特殊類(lèi)的設(shè)計(jì)

 更新時(shí)間:2022年02月25日 15:03:46   作者:小菜雞加油  
這篇文章主要為大家詳細(xì)介紹了C++特殊類(lèi)的設(shè)計(jì),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助

設(shè)計(jì)一個(gè)類(lèi),只能在堆上創(chuàng)建對(duì)象

想要的效果實(shí)際是沒(méi)法直接在棧上創(chuàng)建對(duì)象。

首先cpp只要?jiǎng)?chuàng)建對(duì)象就要調(diào)用構(gòu)造函數(shù),因此先要把構(gòu)造函數(shù)ban掉,把構(gòu)造函數(shù)設(shè)計(jì)成private。但是單這樣自己也創(chuàng)建不了了。

因此提供一個(gè)創(chuàng)建的接口,只能調(diào)用該接口,該接口內(nèi)部寫(xiě)new。而且要調(diào)用該接口需要先有對(duì)象指針調(diào)用,而要有對(duì)象先得調(diào)用構(gòu)造函數(shù)實(shí)例化,因此必須設(shè)計(jì)成靜態(tài)函數(shù)。

但是注意這樣還有拷貝函數(shù)可以調(diào)用HeapOnly copy(*p)。此時(shí)生成的也是棧上的對(duì)象。因此要拷貝構(gòu)造私有,并且只聲明不實(shí)現(xiàn)(實(shí)現(xiàn)也是可以的,但是沒(méi)人用)。這種方式在c++98中叫防拷貝,比如互斥鎖。

#include<iostream>
using namespace std;
class HeapOnly
{
private:
	HeapOnly()
	{ }
    //C++98——防拷貝
    HeapOnly(const HeapOnly&);
public:
	static HeapOnly* CreateObj()
	{
		return new HeapOnly;
	}
};
int main()
{
	HeapOnly* p = HeapOnly::CreateObj();
	return 0;
}

對(duì)于防拷貝,C++11中有新的方式。函數(shù)=delete。

#include<iostream>
using namespace std;
class HeapOnly
{
private:
	HeapOnly()
	{ }
public:
	static HeapOnly* CreateObj()
	{
		return new HeapOnly;
	}
    //C++11——防拷貝
    HeapOnly(const HeapOnly&) =delete;
};
int main()
{
	HeapOnly* p = HeapOnly::CreateObj();
	return 0;
}

總結(jié):

1.將類(lèi)的構(gòu)造函數(shù)私有,拷貝構(gòu)造聲明成私有。防止別人調(diào)用拷貝在棧上生成對(duì)象。

2.提供一個(gè)靜態(tài)的成員函數(shù),在該靜態(tài)成員函數(shù)中完成堆對(duì)象的創(chuàng)建

設(shè)計(jì)一個(gè)類(lèi),只能在棧上創(chuàng)建對(duì)象

  • 方法一:同上將構(gòu)造函數(shù)私有化,然后設(shè)計(jì)靜態(tài)方法創(chuàng)建對(duì)象返回即可。

由于返回臨時(shí)對(duì)象,因此不能禁掉拷貝構(gòu)造。

class StackOnly 
{ 
    public: 
    static StackOnly CreateObject() 
    { 
        return StackOnly(); 
    }
    private:
    StackOnly() {}
};
  • 方法二:調(diào)用類(lèi)自己的專(zhuān)屬的operator new和operator delete,設(shè)置為私有。

因?yàn)閚ew在底層調(diào)用void* operator new(size_t size)函數(shù),只需將該函數(shù)屏蔽掉即可。注意:也要防止定位new。new先調(diào)用operator new申請(qǐng)空間,然后調(diào)用構(gòu)造函數(shù)。delete先調(diào)用析構(gòu)函數(shù)釋放對(duì)象所申請(qǐng)的空間,再調(diào)用operator delete釋放申請(qǐng)的對(duì)象空間。

class StackOnly 
{ 
    public: 
    StackOnly() {}
    private: //C++98
    void* operator new(size_t size);
    void operator delete(void* p);
};
int main()
{
  	static StackOnly st;//缺陷,沒(méi)有禁掉靜態(tài)區(qū)的。  
}
class StackOnly 
{ 
    public: 
    StackOnly() {}
    //C++11
    void* operator new(size_t size) = delete;
    void operator delete(void* p) = delete;
};
int main()
{
  	static StackOnly st;//缺陷,沒(méi)有禁掉靜態(tài)區(qū)的。  
}

設(shè)計(jì)一個(gè)類(lèi),不能被拷貝

拷貝只會(huì)放生在兩個(gè)場(chǎng)景中:拷貝構(gòu)造函數(shù)以及賦值運(yùn)算符重載,因此想要讓一個(gè)類(lèi)禁止拷貝,只需讓該類(lèi)不能調(diào)用拷貝構(gòu)造函數(shù)以及賦值運(yùn)算符重載即可。

  • C++98將拷貝構(gòu)造函數(shù)與賦值運(yùn)算符重載只聲明不定義,并且將其訪(fǎng)問(wèn)權(quán)限設(shè)置為私有即可。
class CopyBan
{
    // ...
    private:
    CopyBan(const CopyBan&);
    CopyBan& operator=(const CopyBan&);
    //...
};

原因:

1.設(shè)置成私有:如果只聲明沒(méi)有設(shè)置成private,用戶(hù)自己如果在類(lèi)外定義了,就可以不能禁止拷貝了

2.只聲明不定義:不定義是因?yàn)樵摵瘮?shù)根本不會(huì)調(diào)用,定義了其實(shí)也沒(méi)有什么意義,不寫(xiě)反而還簡(jiǎn)單,而且如果定義了就不會(huì)防止成員函數(shù)內(nèi)部拷貝了。

  • C++11擴(kuò)展delete的用法,delete除了釋放new申請(qǐng)的資源外,如果在默認(rèn)成員函數(shù)后跟上=delete,表示讓編譯器刪除掉該默認(rèn)成員函數(shù)。
class CopyBan
{
    // ...
    CopyBan(const CopyBan&)=delete;
    CopyBan& operator=(const CopyBan&)=delete;
    //...
};

設(shè)計(jì)一個(gè)類(lèi),不能繼承

C++98

// C++98中構(gòu)造函數(shù)私有化,派生類(lèi)中調(diào)不到基類(lèi)的構(gòu)造函數(shù)。則無(wú)法繼承
class NonInherit
{
    public:
    static NonInherit GetInstance()
    {
        return NonInherit();
    }
    private:
    NonInherit()
    {}
};
class B : public NonInherit
{};
int main()
{
    //C++98中這個(gè)不能被繼承的方式不夠徹底,實(shí)際是可以繼承,限制的是子類(lèi)繼承后不能實(shí)例化對(duì)象
    B b;
    return 0;
}

C++11為了更直觀(guān),加入了final關(guān)鍵字

class A final
{   };
class C: A
{};

設(shè)計(jì)一個(gè)類(lèi),只能創(chuàng)建一個(gè)對(duì)象(單例模式)

之前接觸過(guò)了適配器模式和迭代器模式。

可以再看看工廠(chǎng)模式,觀(guān)察者模式等等常用一兩個(gè)的。

單例模式的概念

設(shè)計(jì)模式:設(shè)計(jì)模式(Design Pattern)是一套被反復(fù)使用、多數(shù)人知曉的、經(jīng)過(guò)分類(lèi)的、代碼設(shè)計(jì)經(jīng)驗(yàn)的總結(jié)。

為什么會(huì)產(chǎn)生設(shè)計(jì)模式這樣的東西呢?就像人類(lèi)歷史發(fā)展會(huì)產(chǎn)生兵法。最開(kāi)始部落之間打仗時(shí)都是人拼人的對(duì)砍。后來(lái)春秋戰(zhàn)國(guó)時(shí)期,七國(guó)之間經(jīng)常打仗,就發(fā)現(xiàn)打仗也是有套路的,后來(lái)孫子就總結(jié)出了《孫子兵法》。孫子兵法也是類(lèi)似。

使用設(shè)計(jì)模式的目的:為了代碼可重用性、讓代碼更容易被他人理解、保證代碼可靠性。

設(shè)計(jì)模式使代碼編寫(xiě)真正工程化;設(shè)計(jì)模式是軟件工程的基石脈絡(luò),如同大廈的結(jié)構(gòu)一樣。

  • 單例模式

一個(gè)類(lèi)只能創(chuàng)建一個(gè)對(duì)象,即單例模式,該模式可以保證系統(tǒng)中該類(lèi)只有一個(gè)實(shí)例,并提供一個(gè)訪(fǎng)問(wèn)它的全局訪(fǎng)問(wèn)點(diǎn),該實(shí)例被所有程序模塊共享。比如在某個(gè)服務(wù)器程序中,該服務(wù)器的配置信息存放在一個(gè)文件中,這些配置數(shù)據(jù)由一個(gè)單例對(duì)象統(tǒng)一讀取,然后服務(wù)進(jìn)程中的其他對(duì)象再通過(guò)這個(gè)單例對(duì)象獲取這些配置信息,這種方式簡(jiǎn)化了在復(fù)雜環(huán)境下的配置管理。

1.如何保證全局(一個(gè)進(jìn)程中)只有一個(gè)唯一的實(shí)例對(duì)象

參考只能在堆上創(chuàng)建對(duì)象和在棧上創(chuàng)建對(duì)象,禁止構(gòu)造和拷貝構(gòu)造及賦值。

提供一個(gè)GetInstance獲取單例對(duì)象。

2.如何提供只有一個(gè)實(shí)例呢?

餓漢模式和懶漢模式。

單例模式的實(shí)現(xiàn)

餓漢模式

餓漢模式:程序開(kāi)始main執(zhí)行之前就創(chuàng)建單例對(duì)象,提供一個(gè)靜態(tài)指向單例對(duì)象的成員指針,初始時(shí)new一個(gè)對(duì)象給它。

class Singleton
{
    public:
    	static Singleton* GetInstance()
        {
            return _inst;
        }
    	void Print()
        {
            cout<<"Print() "<<_val<<endl;
        }
    private:
    	Singleton()
        :_val(0)
        {}
    	Singleton(const Singleton& ) =delete;
    	Singleton(const Singleton& ) =delete;
    	static Singleton* _inst;
    	int _val;
};
Singleton* Singleton::_inst = new Singleton;
int main()
{
    cout<<Singleton::GetInstance()<<endl;
    cout<<Singleton::GetInstance()<<endl;
    cout<<Singleton::GetInstance()<<endl;
    Singleton::GetInstance()->Print();
}

懶漢模式

懶漢模式

懶漢模式出現(xiàn)的原因,單例類(lèi)的構(gòu)造函數(shù)中要做很多配置初始化工作,那么餓漢就不合適了,會(huì)導(dǎo)致程序啟動(dòng)很慢。

linux是Posix的pthread庫(kù),windows下有自己的線(xiàn)程庫(kù)。因此要使用條件編譯保證兼容性。因此c++11為了規(guī)范提供了語(yǔ)言級(jí)別的封裝(本質(zhì)也是條件編譯,庫(kù)里實(shí)現(xiàn)了)。

關(guān)于保護(hù)第一次需要加鎖,后面都不需要加鎖的場(chǎng)景的可以使用雙檢查加鎖。

#include<mutex>
#ifdef _WIN32
//windos 提供多線(xiàn)程api
#else
//linux pthread
#endif //
class Singleton
{
    public:
    	static Singleton* GetInstance()
        {
            //保護(hù)第一次需要加鎖,后面都不需要加鎖的場(chǎng)景,可以使用雙檢查加鎖
            //特點(diǎn):第一次加鎖,后面不加鎖,保護(hù)線(xiàn)程安全,同時(shí)提高了效率
            if( _inst == nullptr)
            {
                _mtx.lock();
                if( _inst == nullptr ) 
                {
                    _inst = new Singleton;
                }
                _ntx.unlock();
            }
            return _inst;
        }
    	void Print()
        {
            cout<<"Print() "<<_val<<endl;
        }
    private:
    	Singleton()
        :_val(0)
        {}
    	Singleton(const Singleton& ) =delete;
    	Singleton(const Singleton& ) =delete;
    	static Singleton* _inst;
    	static std::mutex _mtx;
    	int _val;
};
Singleton* Singleton::_inst = nullptr;
std::mutex Singleton::_mtx;//()默認(rèn)無(wú)參構(gòu)造函數(shù)
int main()
{
    Singleton::GetInstance()->Print();
}

餓漢模式和懶漢模式的對(duì)比

  • 餓漢模式
    • 優(yōu)點(diǎn):簡(jiǎn)單
    • 缺點(diǎn):
      • 如果單例對(duì)象構(gòu)造函數(shù)工作比較多,會(huì)導(dǎo)致程序啟動(dòng)慢,遲遲進(jìn)不了入口main函數(shù)。
      • 如果有多個(gè)單例對(duì)象,他們之間有初始化的依賴(lài)關(guān)系,餓漢模式也會(huì)有問(wèn)題。比如有A和B兩個(gè)單例類(lèi),要求A單例先初始化,B必須在A(yíng)之后初始化,那么餓漢無(wú)法保證。這種場(chǎng)景下用懶漢模式,懶漢可以先調(diào)用A::GetInstance(),再調(diào)用B::GetInstance()。
  • 懶漢模式
    • 優(yōu)點(diǎn):解決了餓漢的缺點(diǎn),因?yàn)樗堑谝淮握{(diào)用GetInstance時(shí)創(chuàng)建初始化單例對(duì)象
    • 缺點(diǎn):相對(duì)餓漢復(fù)雜一點(diǎn)。

懶漢模式的優(yōu)化

實(shí)現(xiàn)了”更懶“。

缺點(diǎn):?jiǎn)卫龑?duì)象在靜態(tài)區(qū),如果單例對(duì)象太大,不合適。再挑挑刺,這個(gè)靜態(tài)對(duì)象無(wú)法主動(dòng)控制釋放。

#include<mutex>
#ifdef _WIN32
//windos 提供多線(xiàn)程api
#else
//linux pthread
#endif //
//其他版本懶漢
class Singleton
{
    public:
    	static Singleton* GetInstance()
        {
            static Singleton inst;
            return &inst;
        }
    	void Print()
        {
            cout<<"Print() "<<_val<<endl;
        }
    private:
    	Singleton()
        :_val(0)
        {}
    	Singleton(const Singleton& ) =delete;
    	Singleton(const Singleton& ) =delete;
    	static std::mutex _mtx;
    	int _val;
};
std::mutex Singleton::_mtx;//()默認(rèn)無(wú)參構(gòu)造函數(shù)
int main()
{
    Singleton::GetInstance()->Print();
}
#include<mutex>
#ifdef _WIN32
//windos 提供多線(xiàn)程api
#else
//linux pthread
#endif //
//其他版本懶漢
class Singleton
{
    public:
    	static Singleton* GetInstance()
        {
            static Singleton inst;
            return &inst;
        }
    	void Print()
        {
            cout<<"Print() "<<_val<<endl;
        }
    private:
    	Singleton()
        :_val(0)
        {}
    	Singleton(const Singleton& ) =delete;
    	Singleton(const Singleton& ) =delete;
    	static std::mutex _mtx;
    	int _val;
};
std::mutex Singleton::_mtx;//()默認(rèn)無(wú)參構(gòu)造函數(shù)
int main()
{
    Singleton::GetInstance()->Print();
}

單例對(duì)象的釋放

單例對(duì)象一般不需要釋放。全局一直用的不delete也沒(méi)問(wèn)題,進(jìn)程如果正常銷(xiāo)毀,進(jìn)程會(huì)釋放對(duì)應(yīng)資源。

單例對(duì)象的直接釋放

#include<mutex>
#ifdef _WIN32
//windos 提供多線(xiàn)程api
#else
//linux pthread
#endif //
class Singleton
{
    public:
    	static Singleton* GetInstance()
        {
            //保護(hù)第一次需要加鎖,后面都不需要加鎖的場(chǎng)景,可以使用雙檢查加鎖
            //特點(diǎn):第一次加鎖,后面不加鎖,保護(hù)線(xiàn)程安全,同時(shí)提高了效率
            if( _inst == nullptr)
            {
                _mtx.lock();
                if( _inst == nullptr ) 
                {
                    _inst = new Singleton;
                }
                _ntx.unlock();
            }
            return _inst;
        }
    	static void DelInstance()/*調(diào)的很少,可以雙檢查也可以不雙檢查*/
        {
            _mtx.lock();
            if(!_inst)
            {
                delete _inst;
                _inst=nullptr;
            }
            _mtx.unlock();
        }
    	void Print()
        {
            cout<<"Print() "<<_val<<endl;
        }
    private:
    	Singleton()
        :_val(0)
        {
          	//假設(shè)單例類(lèi)構(gòu)造函數(shù)中,需要做很多配置初始化   
        }
    	~Singletion()
        {
            //程序結(jié)束時(shí),需要處理一下,持久化保存一些數(shù)據(jù)
        }
    	Singleton(const Singleton& ) =delete;
    	Singleton(const Singleton& ) =delete;
    	static Singleton* _inst;
    	static std::mutex _mtx;
    	int _val;
};
Singleton* Singleton::_inst = nullptr;
std::mutex Singleton::_mtx;//()默認(rèn)無(wú)參構(gòu)造函數(shù)
int main()
{
    Singleton::GetInstance()->Print();
}

內(nèi)部垃圾回收類(lèi)

上述場(chǎng)景其實(shí)還是可以擴(kuò)展的。

假設(shè)析構(gòu)函數(shù)有一些數(shù)據(jù)需要保存一下,持久化一下,不調(diào)用析構(gòu)函數(shù)會(huì)存在問(wèn)題,因此需要調(diào)用析構(gòu)函數(shù)的時(shí)候處理。這就得保證main函數(shù)結(jié)束的時(shí)候保證調(diào)用析構(gòu)(private)。

但是顯式調(diào)用DelInstance可能會(huì)存在遺忘。

#include<mutex>
#ifdef _WIN32
//windos 提供多線(xiàn)程api
#else
//linux pthread
#endif //
class Singleton
{
    public:
    	static Singleton* GetInstance()
        {
            //保護(hù)第一次需要加鎖,后面都不需要加鎖的場(chǎng)景,可以使用雙檢查加鎖
            //特點(diǎn):第一次加鎖,后面不加鎖,保護(hù)線(xiàn)程安全,同時(shí)提高了效率
            if( _inst == nullptr)
            {
                _mtx.lock();
                if( _inst == nullptr ) 
                {
                    _inst = new Singleton;
                }
                _ntx.unlock();
            }
            return _inst;
        }
    	void Print()
        {
            cout<<"Print() "<<_val<<endl;
        }
    private:
    	Singleton()
        :_val(0)
        {
          	//假設(shè)單例類(lèi)構(gòu)造函數(shù)中,需要做很多配置初始化   
        }
    	~Singletion()
        {
            //程序結(jié)束時(shí),需要處理一下,持久化保存一些數(shù)據(jù)
        }
    	Singleton(const Singleton& ) =delete;
    	Singleton(const Singleton& ) =delete;
    	//實(shí)現(xiàn)一個(gè)內(nèi)嵌垃圾回收類(lèi)
    	class CGarbo{
            public:
            	~CGarbo()
                {
                    //DelInstance();
                	if(_inst)
                    {
                         delete _inst;
                        _inst = nullptr;
                    }
                }
        }
    	static Singleton* _inst;
    	static std::mutex _mtx;
    	static GCarbo _gc;//定義靜態(tài)gc對(duì)象,幫助我們進(jìn)行回收
    	int _val;
};
Singleton* Singleton::_inst = nullptr;
std::mutex Singleton::_mtx;//()默認(rèn)無(wú)參構(gòu)造函數(shù)
Singleton::CGarbo Singleton::_gc;
int main()
{
    Singleton::GetInstance()->Print();
}

總結(jié)

本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!   

相關(guān)文章

  • 通過(guò)c++11改進(jìn)我們的模式之改進(jìn)命令模式

    通過(guò)c++11改進(jìn)我們的模式之改進(jìn)命令模式

    這篇我要講的是如何使用c++11改進(jìn)命令模式,感興趣的朋友可以看下
    2013-11-11
  • C語(yǔ)言中的getchar和putchar的使用方法

    C語(yǔ)言中的getchar和putchar的使用方法

    這篇文章主要介紹了C語(yǔ)言中的getchar和putchar的使用方法的相關(guān)資料,希望通過(guò)本文能幫助到大家,需要的朋友可以參考下
    2017-10-10
  • C++中多線(xiàn)程的執(zhí)行順序如你預(yù)期嗎

    C++中多線(xiàn)程的執(zhí)行順序如你預(yù)期嗎

    這篇文章主要為大家詳細(xì)介紹一下C++中多線(xiàn)程的執(zhí)行順序的相關(guān)資料,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)C++多線(xiàn)程有一定幫助,需要的可以參考一下
    2022-10-10
  • 詳解C++ 運(yùn)算符重載中返回值的坑

    詳解C++ 運(yùn)算符重載中返回值的坑

    這篇文章主要介紹了C++ 運(yùn)算符重載中返回值的坑,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • C++實(shí)現(xiàn)電子時(shí)鐘效果

    C++實(shí)現(xiàn)電子時(shí)鐘效果

    這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)電子時(shí)鐘效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • C++讀入XML文件示例

    C++讀入XML文件示例

    本篇文章主要介紹了C++讀入XML文件,讀取和設(shè)置xml配置文件是最常用的操作,TinyXML是一個(gè)開(kāi)源的解析XML的C++解析庫(kù),感興趣的小伙伴們可以參考一下。
    2016-12-12
  • C語(yǔ)言寫(xiě)一個(gè)散列表

    C語(yǔ)言寫(xiě)一個(gè)散列表

    這篇文章主要介紹了C語(yǔ)言寫(xiě)一個(gè)散列表,散列表,就是下標(biāo)可以為字母的數(shù)組。更多內(nèi)容和小編一起學(xué)習(xí)下面內(nèi)容吧
    2022-01-01
  • C++ STL標(biāo)準(zhǔn)庫(kù)std::vector的使用詳解

    C++ STL標(biāo)準(zhǔn)庫(kù)std::vector的使用詳解

    vector 是表示可以改變大小的數(shù)組的序列容器,本文主要介紹了C++ STL標(biāo)準(zhǔn)庫(kù)std::vector的使用詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • 簡(jiǎn)述C語(yǔ)言中system()函數(shù)與vfork()函數(shù)的使用方法

    簡(jiǎn)述C語(yǔ)言中system()函數(shù)與vfork()函數(shù)的使用方法

    這篇文章主要介紹了簡(jiǎn)述C語(yǔ)言中system()函數(shù)與vfork()函數(shù)的使用方法,是C語(yǔ)言入門(mén)學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2015-08-08
  • C++數(shù)據(jù)封裝以及定義結(jié)構(gòu)的詳細(xì)講解

    C++數(shù)據(jù)封裝以及定義結(jié)構(gòu)的詳細(xì)講解

    這篇文章主要詳細(xì)講解了C++數(shù)據(jù)封裝以及定義結(jié)構(gòu),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-05-05

最新評(píng)論