C++特殊類設計(單例模式等)

目錄

引言

1.請設計一個類,不能被拷貝

2. 請設計一個類,只能在堆上創建對象

為什么設置實例的方法為靜態成員呢

3. 請設計一個類,只能在棧上創建對象

4. 請設計一個類,不能被繼承

5. 請設計一個類,只能創建一個對象(單例模式)

餓漢模式

懶漢模式

單例對象一般不考慮析構

為什么私有析構呢?


引言

在當今的軟件開發實踐中,特殊類設計模式扮演著至關重要的角色,它們不僅提高了代碼的可維護性和可擴展性,還確保了系統的穩定性和性能。其中,單例模式作為最常用的設計模式之一,以其獨特的實例管理方式,成為了許多場景下的首選解決方案。本文旨在探討C++中單例模式及其他特殊類設計的精髓,通過分析其背后的設計哲學和實現技巧,幫助讀者掌握這些高級編程技巧,以提升其在軟件開發過程中的設計能力和代碼質量。

在我們設計一個特殊類的時候,一般要把構造、拷貝和賦值私有保護,防止被其他類拷貝或者產生不想要(意料之外)的錯誤。

1.請設計一個類,不能被拷貝

拷貝只會放生在兩個場景中:拷貝構造函數以及賦值運算符重載,因此想要讓一個類禁止拷貝,

只需讓該類不能調用拷貝構造函數以及賦值運算符重載即可
C++98
將拷貝構造函數與賦值運算符重載只聲明不定義,并且將其訪問權限設置為私有即可。
class CopyBan
{// ...private:CopyBan(const CopyBan&);CopyBan& operator=(const CopyBan&);//...
};

C++11

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

同時我們還可以設置一個基類,讓子類繼承基類,讓子類正常實現功能,設置基類不可被拷貝即可。

2. 請設計一個類,只能在堆上創建對象

實現方式:
1. 將類的構造函數私有,拷貝構造聲明成私有。防止別人調用拷貝在棧上生成對象。
2. 提供一個靜態的成員函數,在該靜態成員函數中完成堆對象的創建。
只能在堆上創建對象,即只能new對象,不允許在棧上創建臨時變量。當然要禁用拷貝、構造、賦值函數(非單例)
class HeapOnly ? ?
{ ? ? 
public: ? ? static HeapOnly* CreateObject() ?{ ? ? ?return new HeapOnly; ? ?}
private: ? ?HeapOnly() {}// C++98// 1.只聲明,不實現。因為實現可能會很麻煩,而你本身不需要// 2.聲明成私有HeapOnly(const HeapOnly&);// or// C++11 ? ?HeapOnly(const HeapOnly&) = delete;
}

由于沒有this指針,無法調用構造,而是只是去new這個鍍錫,由系統去完成資源的申請


靜態不能調用非靜態就是因為沒有this指針,缺少調用的參數

但是new和delete這種操作不需要this指針

那每次調的時候,返回的都是一個新的靜態對象嗎?--- NO!這個方法是靜態的,但是返回的變量不是靜態的

為什么設置實例的方法為靜態成員呢

收線確定的是,一定是內部new創建的對象。

因為如果設置為非靜態成員,那就只能通過對象去調用,但是我們不能去在棧區創建對象。

并且構造私有,外部一定不可以創建對象,只能用類調用,所以必須靜態!

為什么禁用拷貝構造:比如A a1(a2);這樣a1依然是在棧區!

3. 請設計一個類,只能在棧上創建對象

只能通過類型創建,禁止new對象

方法一:同上將構造函數私有化,然后設計靜態方法創建對象返回即可
依然需要把構造私有,需要注意的是,不能把構造和拷貝工構造私有
class StackOnly
{
public:static StackOnly CreateObj(){StackOnly obj;return obj;}void* operator new(size_t size) = delete;void operator delete(void* p) = delete;
private:StackOnly() ?:_a(0){}
private:int _a;
};

1.設置為靜態:

并且構造私有,外部一定不可以創建對象,只能用類調用,所以必須靜態!

2.為什么不可以禁用拷貝構造:比如A a1(a2);這樣a1依然是在棧區!符合要求,并且匿名對象的聲明周期只在這一行!為了防止匿名對象周期太短,無法進行較好的連續性開發,所以需要賦值給另一個棧區的對象。

3.可以返回臨時對象,只需要賦值給其他對象即可(棧區);也可以返回非匿名對象,也是采用賦值的方式進行連續性開發。

4.為了防止創建堆區對象,需要禁用new和delete(為了防止創建棧區對象時,需要禁用拷貝、賦值)

????????

4. 請設計一個類,不能被繼承

C++98方式

// C++98中構造函數私有化,派生類中調不到基類的構造函數。則無法繼承
class NonInherit
{
public:static NonInherit GetInstance(){return NonInherit();}
private:NonInherit(){}
};
C++11方法
final關鍵字, final修飾類,表示該類不能被繼承。
class A ?final
{// ....
};

5. 請設計一個類,只能創建一個對象(單例模式)

設計模式:
設計模式(Design Pattern)是一套 被反復使用、多數人知曉的、經過分類的、代碼設計經驗的
總結。為什么會產生設計模式這樣的東西呢?就像人類歷史發展會產生兵法。最開始部落之間打
仗時都是人拼人的對砍。后來春秋戰國時期,七國之間經常打仗,就發現打仗也是有 套路的,后
來孫子就總結出了《孫子兵法》。孫子兵法也是類似。
使用設計模式的目的:為了代碼可重用性、讓代碼更容易被他人理解、保證代碼可靠性。 設計模
式使代碼編寫真正工程化;設計模式是軟件工程的基石脈絡,如同大廈的結構一樣。
單例模式:
一個類只能創建一個對象,即單例模式,該模式可以保證系統中該類只有一個實例,并提供一個
訪問它的全局訪問點,該實例被所有程序模塊共享。比如在某個服務器程序中,該服務器的配置
信息存放在一個文件中,這些配置數據由一個單例對象統一讀取,然后服務進程中的其他對象再
通過這個單例對象獲取這些配置信息,這種方式簡化了在復雜環境下的配置管理。
單例模式有兩種實現模式:

餓漢模式

餓漢模式:已經餓得不行了,要求立刻有東西吃,即在main函數之前就得創建好---全局

餓漢:設置為全局,提前創建。

既然是單例,一定先把構造私有。

在類的外部雖然不能創建全局的對象,但是在類的內部可以創建。----思路:類的內部聲明靜態成員,類的外部定義,這樣就是一個全局的數據。

demo
// 懶漢模式:第一次用的時候再創建(現吃現做)
class A {
public:static A* GetInstance() {return _inst;}
private:A() {}map<string, string> _dict;int _n = 0;static A* _inst;
};

我們在類的內部創建對象的時候,當然不能

? ?class? ? ? ? A

? ? ? ? A? ?_a;

??}

這樣屬于嵌套定義。
但是也不能內部用靜態成員方法去獲取,因為函數需要在主函數內調用。
當我們在內部使用靜態成員的時候,當然不是嵌套定義,因為靜態不屬于某個對象,而是屬于整個類。并且,我們只能是在類內聲明,并沒有定義,需要在類的外部定義。
在類的外部定義的時候,只需要點名:類型 + 作用域即可,不需要再次聲明靜態,靜態只需要聲明一次即可,但是定義(實例化),必須使用類型。
當需要使用這個實例的時候,調用實例方法去獲取即可。
總結:
1.類內聲明靜態,類外實例化靜態(全局)
2.類內提供獲取實例的犯法
同時刪除拷貝構造和賦值

訪問成員需要借助對象,這時候就需要調用GetInstance函數

優點:創建簡單?

缺點:1.進程啟動慢

?????????? 2.一旦存在兩個全局單例,不能控制單例啟動的先后順序。

懶漢模式

現吃現做,不著急,main函數內創建。

? 只需要把靜態的對象換成指針即可,獲取實例的時候,如果指針是nullptr,那么創建,如果不是,那么直接返回

線程不安全,兩個線程同時進來,可能會new兩個對象---加鎖

單例對象一般不考慮析構

惡漢不存在釋放的問題--全局,

懶漢對象也一般不需要釋放---單例對象一般是生命周期伴隨整個程序,對整個程序都起到至關重要的作用,進程結束時,會自動釋放。

就算要釋放,如果我們期望既可以手動釋放(析構不能手動釋放),也可以在main函數結束時自動釋放

class B
{
public:static B* GetInstance(){if (_inst == nullptr){_inst = new B;}return _inst;}static void DelInstance(){if (_inst){delete _inst;_inst = nullptr;}}private:B(){}~B(){// 持久化:要求把數據寫到文件cout << "數據寫到文件" << endl;}B(const B& aa) = delete;B& operator=(const B& aa) = delete;map<string, string> _dict;int _n = 0;static B* _inst;class gc{public:~gc(){DelInstance();}};static gc _gc;
};B* B::_inst = nullptr;
B::gc B::_gc;

可以私有析構函數

提供一個調用析構函數的接口DelInstance,我們可以手動調用這個接口去進行析構。

我們新建一個內部類,這個內部類是外部類的友元,可以訪問私有。等main函數結束的時候_gc調用析構,析構會調用DelInstance。

這樣可以做到:1.顯示釋放(析構不允許顯示調用,但是delete指針的時候,可以調用析構)

? ? ? ? ? ? ? ? ? ? ? ? 2.沒有顯示釋放,等程序結束也會釋放

為什么私有析構呢?

B* instance = B::GetInstance();
delete instance;

B* instance2 = B::GetInstance();

如果是public的話,每個人可以自己delete這個,那么就違背單例模式的原則了!

而這塊放的這個DelInstance函數是意思萬一情況下,不使用單例了,自己想釋放的話,可以通過這個函數釋放,但是一般也不會這樣做的,一般gc就替咱們回收了

總之就是:不能讓其他人去隨便delete單例,所以私有;同時希望gc能夠管理單例,等程序結束,gc清理的時候,gc會協助清理單例

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/63409.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/63409.shtml
英文地址,請注明出處:http://en.pswp.cn/web/63409.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

分布式系統架構:服務容錯

1.為什么需要容錯 分布式系統的本質是不可靠的&#xff0c;一個大的服務集群中&#xff0c;程序可能崩潰、節點可能宕機、網絡可能中斷&#xff0c;這些“意外情況”其實全部都在“意料之中”。故障的發生是必然的&#xff0c;所以需要設計一套健壯的容錯機制來應對這些問題。 …

【Latex手冊】自用

收錄Latex使用文檔/工具 個人使用時候的tips&#xff0c;僅供個人使用 核心網頁&#xff1a;LaTeX 工作室 【1】首頁 | LaTeX 知識庫 &#xff08;有詳細的入門教程&#xff09; 【2】LaTeX工作室 - LaTeX工作室&#xff08;一些模板&#xff09; 【3】LaTeX 工作室 &…

Pytorch應用實戰(1)- 基于YOLO的視頻人臉馬賽克處理

免費鏈接: Blogger(需翻Q), Github 文章目錄 本文介紹給圖片的人臉打碼給視頻的人臉打碼本文介紹 YoloV11(Github)提供了非常方便的API幫助用戶實現目標檢測(detect)、語義分割(segement)、肢體識別(Pose)等功能。 本文將基于YoloV11的目標檢測來實現一個視頻人臉馬…

[IT項目管理]九.項目質量管理

九&#xff0e;項目質量管理 9.1項目質量管理的重要性 對于很多IT項目的差勁&#xff0c;大多數人只可以忍受。項目質量管理是IT項目管理的重要組成部分&#xff0c;對于提高項目成功率、降低項目成本、提升客戶滿意度至關重要。盡管很多人對IT項目的質量問題感到無奈&#x…

【Threejs】從零開始(六)--GUI調試開發3D效果

請先完成前置步驟再進行下面操作&#xff1a;【Threejs】從零開始&#xff08;一&#xff09;--創建threejs應用-CSDN博客 一.GUI界面概述 GUI&#xff08;Graphical User Interface&#xff09;指的是圖形化用戶界面&#xff0c;廣泛用在各種程序的上位機&#xff0c;能夠通過…

ffmpeg-SDL顯示BMP

效果圖如下 本文主要將我們通過創建窗口、渲染上下文工具、紋理工具、矩形框工具&#xff1b;其需要主要的是&#xff1a;首先我們在顯示BMP時&#xff0c;需要先創建好窗口&#xff0c;再使用渲染工具對窗口進行格式刷&#xff0c;使用紋理工具和渲染工具配合進行BMP圖片顯示…

多音軌視頻使用FFmpeg刪除不要音軌方法

近期給孩子找宮崎駿動畫&#xff0c;但是有很多是多音軌視頻但是默認的都是日語&#xff0c;電視上看沒辦法所以只能下載后刪除音軌文件只保留中文。 方法分兩步&#xff0c;先安裝FFmpeg在轉文件即可。 第一步FFmpeg安裝 FFmpeg是一個開源項目&#xff0c;包含了處理視頻的…

基礎二分查找總結題-單峰序列2類做法

&#x1f330;單峰序列題目描述 晴問算法 題目描述&#xff1a; 單峰序列是指&#xff0c;在這個序列中存在一個位置&#xff0c;滿足這個位置的左側&#xff08;含該位置&#xff09;是嚴格遞增的、右側&#xff08;含該位置&#xff09;是嚴格遞減的&#xff0c;這個位置被…

【SH】Ubuntu Server 24搭建Web服務器訪問Python程序研發筆記

文章目錄 說個問題寫個方案一、安裝Ubuntu Server二、安裝Web服務器采用Nginx服務器 三、安裝Python及依賴創建項目虛擬環境 四、安裝Python Web框架采用Flask框架創建和運行Flask應用&#xff08;以后的重點&#xff09; 五、安裝WSGI服務器采用Gunicorn 六、配置Nginx七、驗證…

Vue3 重置ref或者reactive屬性值

需要重新定義一個對象綁定復制給原對象 。 實例代碼: const data () > ({groupId: ,groupCode: ,groupName: ,groupType: ,});const formData ref(data());//重置對象值 const reset()>{Object.assign(formData, data()…

C#速成(GID+圖形編程)

常用類 類說明Brush填充圖形形狀,畫刷GraphicsGDI繪圖畫面&#xff0c;無法繼承Pen定義繪制的對象直線等&#xff08;顏色&#xff0c;粗細&#xff09;Font定義文本格式&#xff08;字體&#xff0c;字號&#xff09; 常用結構 結構說明Color顏色Point在平面中定義點Rectan…

vue iframe進行父子頁面通信并切換URL

使用通義千問提問后得到一個很好的示例。 需求是2個項目需要使用同一個面包屑進行跳轉&#xff0c;其中一個是iframe所在的項目&#xff0c;另一個需要通過地址訪問。通過 window.parent.postMessage &#xff0c;幫助 <iframe> 內嵌入的子頁面和其父頁面之間進行跨域通…

誰說C比C++快?

看到這個問題&#xff0c;我我得說&#xff1a;這事兒沒有那么簡單。 1. 先把最大的誤區打破 "C永遠比C快" —— 某位1990年代的程序員 這種說法就像"自行車永遠比汽車省油"一樣荒謬。我們來看個例子&#xff1a; // C風格 char* str (char*)malloc(100…

【ADS射頻電路學習筆記】1. ADS基本操作

下面介紹ADS中主要仿真器的使用 1. 直流仿真 直流仿真器在控制面板的simulator-dc 直流仿真器 但是ADS自帶有很多仿真器&#xff0c;可以直接來調用 選用晶體管電流掃描的模板 就可以輸出模板 然后調入晶體管模型 然后要設置掃描的電壓&#xff0c;選擇dc仿真器對vds進行掃描…

CSS學習記錄12

CSS浮動 CSSfloat屬性規定元素如何浮動 CSSclear屬性規定哪些元素可以在清除的元素旁邊以及在哪一側浮動。 float屬性 float屬性用于定位和格式化內容&#xff0c;例如讓圖像向左浮動到容器的文本那里。 float屬性可以設置以下值之一&#xff1a; left - 元素浮動到其容器…

Chinese-Clip實現以文搜圖和以圖搜圖(transformers版)

本文不生產技術&#xff0c;只做技術的搬運工&#xff01; 前言 作者昨天使用cn_clip庫實現了一版&#xff0c;但是覺得大家復現配置環境可能有點復雜&#xff0c;因此有使用transformers庫實現了一版&#xff0c;提供大家選擇&#xff0c;第一篇參考鏈接如下&#xff1a; Ch…

【Unity3D】無限循環列表(擴展版)

基礎版&#xff1a;【Unity技術分享】UGUI之ScrollRect優化_ugui scrollrect 優化-CSDN博客 using UnityEngine; using UnityEngine.UI; using System.Collections.Generic;public delegate void OnBaseLoopListItemCallback(GameObject cell, int index); public class BaseLo…

MSSQL AlwaysOn 可用性組(Availability Group)中的所有副本均不健康排查步驟和解決方法

當遇到 MSSQL AlwaysOn 可用性組(Availability Group)中的所有副本均不健康的情況時(MSSQL AG 副本名稱: All replicas unhealthy),這通常意味著可用性組無法正常工作,數據同步和故障轉移功能可能受到影響。以下是一些可能的原因及相應的排查步驟和解決方法: 1. 檢查副本…

springboot檢測配置是否存在,如果存在則返回,不存在則提示新增

我這里是以七牛為例子 在yml中添加七牛的相關配置 qiniu: #七牛的相關配置accessKey: your_access_keysecretKey: your_secret_keybucket: your_bucket_namedomain: your_domain 對應在給配置文件來一個相應的實體類QiniuConfig Component ConfigurationProperties(prefix &…

[NOIP2016 普及組] 海港 -STL-隊列queue

[NOIP2016 普及組] 海港 題目背景 NOIP2016 普及組 T3 題目描述 小 K 是一個海港的海關工作人員&#xff0c;每天都有許多船只到達海港&#xff0c;船上通常有很多來自不同國家的乘客。 小 K 對這些到達海港的船只非常感興趣&#xff0c;他按照時間記錄下了到達海港的每一…