從C學C++(7)——static成員

從C學C++(7)——static成員

若無特殊說明,本博客所執行的C++標準均為C++11.

static成員和成員函數

對于特定類型的全體對象而言,有時候可能需要訪問一個全局的變量。比如說統計某種類型對象已創建的數量。

通常在C中使用全局變量來實現,如果我們用全局變量會破壞數據的封裝,一般的用戶代碼都可以修改這個全局變量,這時我們可以用類的靜態成員來解決這個問題。

static數據成員存在于類類型的每個對象中static數據成員獨立該類的任意對象存在,它是與類關聯的對象,不與類對象關聯。

個人理解:把它等同于python中類成員就可以了,不過C++中使用static關鍵字其實說明它和一般靜態變量一樣,存在于.bss段或者.data段,生命周期是整個程序(不隨著對象實例創建或者銷毀),所以其是獨立于類對象實例存在的,但只是C++編譯器在語法上把它歸類于某個類(本質在運行時和其他靜態變量無異),需要我們使用類域或者對象實例去訪問(這個功能就和python中的類成員基本一致)。

類的static成員

特點:
  • static成員的名字是在類的作用域中,因此可以避免與其它類成員或全局對象名字沖突
  • 可以實施封裝,static成員可以是私有的,而全局對象不可以
  • 閱讀程序容易看出static成員與某個類相關聯,這種可見性可以清晰地反映程序員的意圖。
定義和注意事項
  • static成員需要在類定義體外進行初始化與定義。

    這個還好理解,因為類定義其實和C中結構類型聲明是類似的,它只是聲明了一種類似,因此,它的static 成員也只是聲明里面有一個static 而已,真正這個獨立于類對象實例的static 成員總得找個地方定義它(畢竟它和一般的成員不一樣,一般的成員跟隨著對象的定義而創建(分配內存空間))。

  • 特殊的整型static const成員:整型static const成員可以在類定義體中初始化和定義。(個人感覺更像是個語法糖,平時還是不用為好,而且只有整形可以,浮點和其它類型不可以,所以還是不用為好)。

枚舉常量類型

在類中定義的枚舉常量類型類似于static const 成員,是常量,而且被所有對象共享,屬于類。

類的static成員函數

  • static 成員函數沒有隱含的this指針。

    因為是類成員函數,不是任何一個特定對象的成員函數,所以自然沒有隱含的this指針,也就意味著,在靜態成員函數中,沒有辦法直接訪問其他非靜態成員(函數)。

  • 靜態成員函數不可以訪問非靜態成員。

  • 非靜態成員函數可以訪問靜態成員。

    具體對象實例可以訪問類變量,也可以訪問類函數一個道理。因為static 聲明的成員(函數)是所有類共享的。

類/對象實例的大小計算

  • 類大小計算遵循前面學過的結構體對齊原則。
  • 類的大小與數據成員有關與成員函數無關。
  • 類的大小與靜態數據成員(函數)無關。
  • 虛函數對類的大小的影響:會使類對象多4個字節的大小,用于存放虛表指針。
  • 虛繼承對類的大小也會有影響。

static用法總結

函數內部修飾變量使其生存期為整個程序(C也一樣)

用于函數內部修飾變量,即函數內的靜態變量這種變量的生存期長于該函數,使得函數具有一定的"狀態”。使用靜態變量的函數一般是不可重入的,也不是線程安全的,比如strtok(3)

函數外部修飾變量使其限制于該文件(C也一樣)

用在文件級別(函數體之外),修飾變量或函數,表示該變量或函數只在本文件可見,其他文件看不到也訪問不到該變量或函數。專業的說法叫“具有internal linkage”(簡言之:不暴露給別的translation unit,C/C++中最小編譯單元為文件)

修飾類的數據成員使其成為類成員(C沒有)

用于修飾類的數據成員,即所謂"靜態成員”。這種數據成員的生存期大于class的對象(實例/instance)。靜態數據成員是每個class有一份,普通數據成員是每個instance 有一份。

修飾類的成員函數使其成為類方法(C沒有)

用于修飾class的成員函數,即所謂“靜態成員函數”。這種成員函數只能訪問靜態成員和其他靜態成員函數,不能訪問非靜態成員和非靜態成員函數。

四種對象的作用域和生存期

棧對象

  • 隱含調用構造/析構函數(程序中沒有顯示調用)
  • 作用域為所屬的{} 的塊作用域內。
  • 生存期跟隨所屬函數的執行(分配空間)和退出(釋放空間)。

堆對象

  • 隱含調用構造/析構函數(程序中沒有顯示調用)。
  • 作用域為所屬的{} 的塊作用域內。
  • 生存期取決于用戶何時delete

全局對象、靜態全局對象

  • 全局對象的構造先于main函數(這個對于支持嵌入式的C++編譯器,會在進入main函數前的啟動匯編代碼中插入執行如__libc_init_array() 等的全局對象初始化函數鏈表執行)。
  • 已初始化的全局變量或靜態全局對象存儲于.data段中。
  • 未初始化的全局變量或靜態全局對象存儲于.bss(Block Started by Symbol)段中。
  • 全局對象和靜態對象的生存期都是整個程序執行期間。

靜態局部對象

  • 已初始化的靜態局部變量存儲于.data段中。
  • 未初始化的靜態局部變量存儲于.bss段中。
  • 對于靜態局部變量,如果是內置類型(整形、浮點等),對象在編譯時就初始化好在.data段中了,但對于靜態局部的(我們自己定義的)類對象實例,其初始化是在代碼運行時完成的。(這個好理解,雖然其存在于.data段而非棧上,但由于類對象實例初始化時需要執行構造函數,而編譯器是沒有辦法執行函數的,只有運行到這段代碼的時候才能執行構造函數,所以其初始化必須推遲到運行時刻)。

static 和單例模式

單例模式

設計模式的一種:保證一個類只有一個實例,并提供一個全局訪問點。(目前暫時沒有想到其的用處,按照之前的經驗,感覺可能在對硬件封裝時可能會有用,畢竟底層真實的硬件可能只有一個)。

在C++中設計單例模式需要注意:禁止構造函數、拷貝函數和=運算符,并提供共一個全局的訪問點

使用static 局部對象和引用返回實現單例模式

class Singleton{
public:static Singleton& getInstance() {static Singleton instance; // 局部靜態變量,保證只創建一次return instance;}~Singleton() {std::cout << "Singleton destroyed." << std::endl;}
private:Singleton(const Singleton& other); // 禁止拷貝構造Singleton& operator=(const Singleton& other); // 禁止賦值操作Singleton() {std::cout << "Singleton created." << std::endl;}
};

static 局部對象(利用其生存期為整個程序),且static 局部對象只會初始化一次的特性。通過返回引用,保證每次getInstance() 函數返回的都是同一個靜態局部對象。需要注意,這里在調用函數的時候,必須使用引用來接收返回值(如果使用對象的話,這里會發生從引用到對象的賦值,而我們已經將拷貝構造函數聲明為private,因此會報錯,達到單例模式的目的)。

同時,因為返回的是引用,所以不存在多個對象釋放的時候出現空指針的問題,在程序結束的時候,只有靜態局部變量被釋放一次,其他都是引用,不存在釋放多次的問題。

Singleton& s1 = Singleton::getInstance(); // 獲取單例實例
Singleton& s2 = Singleton::getInstance(); // 再次獲取同一實例

const 成員函數/對象和mutable

const 成員函數

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

  • const 成員函數只能訪問數據成員的值,不能修改它的值。

  • 需要注意const 成員函數是在函數聲明和函數體之間加上const 關鍵字

    class Test{
    public:int get_x() const{ //這才是const成員函數return x; //且const成員函數內部不能修改數據成員的值}const int get_x1(){return x; // 這個函數只是一個返回const int 類型的成員函數而已,不是const成員函數}
    private:    int x
    }
    

const 對象的使用

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

  • const對象的定義:const 類名 對象名(參數表);

  • const 對象定義的時候默認會把不會修改內部變量的成員函數定義為const 成員函數,而那些修改到內部變量的成員函數則是非const 的,因此,如果const 對象調用那些非const 成員函數則會報錯。

    這個好理解,因為成員函數默認是會傳入一個this指針,那些要修改內部對象的成員函數傳入的指針是非const的,而const對象傳入自身指針是const類型,對C++來說,沒有顯式使用const_cast<>() 去除const 屬性,是不可能完成const到非const的類型轉換的。

mutable 關鍵字

如果我們需要定義個const對象,但這個對象中可能只需要一兩個成員是需要被外界配置修改的,這個時候可以使用 mutable 關鍵字,因為,mutable 修飾的數據成員即使在const對象或在const成員函數中都可以被修改。

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

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

相關文章

大模型和ollama一起打包到一個docker鏡像中

如何將大模型鏡像和 Ollama 鏡像打包在一個 Docker 鏡像中 最近工作中有個需求是將ollama和大模型一起打成一個鏡像部署&#xff0c;將自己的操作步驟分享給大家。將大模型與 Ollama 服務打包在同一個 Docker 鏡像中&#xff0c;可以簡化部署流程并確保環境一致性。下面詳細介…

2025年滲透測試面試題總結-攻防研究員(應用安全)(題目+回答)

安全領域各種資源&#xff0c;學習文檔&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各種好玩的項目及好用的工具&#xff0c;歡迎關注。 目錄 攻防研究員(應用安全) 一、基礎部分 1. HTTP狀態碼對比 2. HTTP請求方法核心作用 3. 網絡分層協議速查表…

SpringBoot新聞項目學習day3--后臺權限的增刪改查以及權限管理分配

新增管理員修改管理員刪除管理員登錄 新增管理員 1.點擊新增按鈕打開一個對話框 2.確定新增對話框要顯示哪些內容 3.提交 4.后端處理、保存 5.響應前端 vue代碼 <template><!-- 新增代碼內容是比較多的,建議抽取出來,定義到一個獨立的vue文件中在列表組件中導入…

算法導論第二十五章 深度學習的倫理與社會影響

第二十五章 深度學習的倫理與社會影響 技術的光芒不應掩蓋倫理的陰影 隨著深度學習技術在各領域的廣泛應用&#xff0c;其引發的倫理和社會問題日益凸顯。本章將深入探討這些挑戰&#xff0c;并提供技術解決方案和最佳實踐&#xff0c;引導讀者構建負責任的人工智能系統。 25.…

Linux中ansible模塊補充和playbook講解

一、模塊使用 1.1 Yum模塊 功能&#xff1a;管理軟件包&#xff0c;只支持RHEL&#xff0c;CentOS&#xff0c;fedora&#xff0c;不支持Ubuntu其它版本 參數說明name要操作的軟件包名稱&#xff0c;支持通配符&#xff08;如 httpd, nginx*&#xff09;&#xff0c;也可以是…

唐代大模型:智能重構下的盛世文明圖譜

引言&#xff1a;當長安城遇見深度學習 一件唐代鎏金舞馬銜杯銀壺的虛擬復原品正通過全息投影技術演繹盛唐樂舞。這個跨越時空的場景&#xff0c;恰似唐代大模型技術的隱喻——以人工智能為紐帶&#xff0c;連接起長安城的盛世氣象與數字時代的文明重構。作為人工智能與歷史學…

國產ARM/RISCV與OpenHarmony物聯網項目(三)網關設備控制

一、設備控制界面與功能設計 程序界面運行與設計效果如下: 設備控制相關程序調用關系圖如下&#xff1a; 其中device_control.html程序為網頁界面顯示程序&#xff0c;led_alarm.cgi程序為光線數據的報警超限數據設置與管理&#xff0c;led_control.cgi程序功能為對Led燈的開…

微信小程序反編譯實戰教程

在實際滲透測試或安全分析中&#xff0c;經常會遇到微信小程序中的簽名加密&#xff08;sign&#xff09;機制&#xff0c;這些機制大多具備防重放、防篡改的特性&#xff0c;導致我們在抓包時難以直接復現請求。 &#x1f50d; 另一方面&#xff0c;一些小程序的代碼中往往會…

【NLP入門系列三】NLP文本嵌入(以Embedding和EmbeddingBag為例)

&#x1f368; 本文為&#x1f517;365天深度學習訓練營 中的學習記錄博客&#x1f356; 原作者&#xff1a;K同學啊 博主簡介&#xff1a;努力學習的22級本科生一枚 &#x1f31f;?&#xff1b;探索AI算法&#xff0c;C&#xff0c;go語言的世界&#xff1b;在迷茫中尋找光芒…

文心一言(ERNIE Bot):百度打造的知識增強大語言模型

1. 產品概述 文心一言&#xff08;ERNIE Bot&#xff09;是百度自主研發的知識增強大語言模型&#xff0c;于2023年3月16日正式發布&#xff0c;對標OpenAI的ChatGPT&#xff0c;具備文本生成、多模態交互、邏輯推理、中文理解等能力。該模型基于百度的飛槳深度學習平臺和文心…

Java-49 深入淺出 Tomcat 手寫 Tomcat 實現【02】HttpServlet Request RequestProcessor

點一下關注吧&#xff01;&#xff01;&#xff01;非常感謝&#xff01;&#xff01;持續更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持續更新中&#xff01;&#xff08;長期更新&#xff09; 目前2025年06月13日更新到&#xff1a; AI煉丹日志-28 - Aud…

在VB.net中,文本插入的幾個自定義函數

一、如果你是高手&#xff0c;一定“識貨”&#xff0c;分享給你 二、可應用于文本插入的幾種方式&#xff1a;6種 三、需要用到以下的幾個函數&#xff1a; 上代碼&#xff1a; Module TextModule <summary> 在指定位置插入文本 </summary> <p…

QC -io 服務器排查報錯方式/報錯: Failed to convert string to integer of varId variable!“

進斷點控制臺有報錯之后&#xff0c;復制報錯信息到 頭部菜單欄 1.編輯 -> 2.Find/Replace ->3.Advanced Find ->4. Project“xxxxx” 能找到問題點 再分析定位 在排查報錯時候&#xff0c;進入了這個報錯&#xff0c;msgInfo "MyTcpRedis: Failed to conver…

c++中auto與decltype使用

在 C11及后續版本中&#xff0c;關鍵字auto和decltype都是用于類型推導的&#xff0c;但它們的使用場景和行為有所不同。 1. auto 關鍵字 作用 auto 用于自動推導變量的類型&#xff0c;由編譯器根據初始化表達式來確定。 常見用法 // 基本用法 auto x 42; // int…

LabVIEW機器視覺零件檢測

基于LabVIEW 圖形化編程平臺與機器視覺技術&#xff0c;構建集圖像采集、處理、尺寸計算與合格性分析于一體的自動化檢測方案。通過模塊化硬件架構與自適應算法設計&#xff0c;實現對機械零件多維度尺寸的非接觸式高精度測量&#xff0c;相比人工檢測效率提升 12 倍&#xff0…

大數據治理域——實時數據開發

摘要 本文深入探討了大數據治理域中的實時數據開發&#xff0c;重點介紹了流式數據處理的核心價值、特點、技術挑戰、典型能力和應用場景。同時&#xff0c;詳細闡述了流式技術架構&#xff0c;包括數據采集、處理、存儲和服務等環節&#xff0c;并針對大促場景提出了相應的技…

Halcon/C# 圖像窗口、讀取圖片及仿射變換

一、Halcon 清理窗口 清除圖像窗口的顯示。 dev_clear_window() 二、Halcon 讀取圖片 (一) 讀取一張圖片 read_image (Image, printer_chip/printer_chip_01)Image&#xff1a;&#xff08;輸出參數&#xff09;讀取到的圖片變量名 第二個參數&#xff1a;圖片路徑&#xf…

Nginx 反向代理服務和安裝docker-compose

Nginx 反向代理服務和安裝docker-compose Nginx Proxy Manager 他是一個可視化的nginx的反向代理神器&#xff0c;動動手指輕松的配置Nginx&#xff0c;我們可以通過一些網頁&#xff0c;即可完成網站的代理配置&#xff0c;無需在動手安裝Nginx&#xff1b; dockoer-compose部…

FPGA基礎 -- Verilog 鎖存器簡介

由淺入深地講解 Verilog 中的鎖存器&#xff08;Latch&#xff09;**&#xff0c;包括&#xff1a; 什么是鎖存器&#xff08;定義與作用&#xff09;鎖存器的分類&#xff08;透明鎖存器 vs 邊沿觸發器&#xff09;Verilog 中鎖存器的建模方式鎖存器與觸發器的區別鎖存器的時…

Eclipse Memory Analyzer (MAT) 相關配置調整

一、JDK版本過低提示 已安裝高于 jdk 17 的版本依舊提示 jdk 版本過低&#xff0c;打開MAT的安裝目錄&#xff0c;在配置文件 MemoryAnalyzer.ini 中添加配置指向JDK即可。新增兩行配置&#xff1a; -vm D:/jdk_21.0.7/bin/javaw.exe //jdk安裝路徑 bin 目錄下的javaw.exe二…