網站首頁 編程語言 正文
靜態成員變量
這里先引用GeeksforGeeks的一段內容:
Static data members are class members that are declared using static keywords. A static member has certain special characteristics. These are:
- Only one copy of that member is created for the entire class and is shared by all the objects of that class, no matter how many objects are created.
- It is initialized before any object of this class is being created, even before main starts.
- It is visible only within the class, but its lifetime is the entire program
語法:?static data_type data_member_name;
靜態變量在任何類對象創建前初始化
我們看代碼示例,一碼勝千言
#include <iostream> using namespace std; class A { public: A() { cout << "A constructed" << endl; } }; class B { static A a; public: B() { cout << "B constructed" << endl; } }; int main() { B b; return 0; } // output B constructed
我們看到B類有一個靜態成員A類,但是在創建B的對象時并沒有調用A的構造函數,原因很簡單,即在類B中僅僅聲明(declare)了靜態類A,但沒有在類外定義(define)它。?如果我們在靜態成員變量定義前使用它,那么會編譯報錯,這和代碼塊中的靜態變量不同,代碼塊中的靜態變量會有常量初始化的過程,代碼示例如下。
#include <iostream> using namespace std; class A { public: int x; A() { cout << "A constructed" << endl; } }; class B { static A a; public: B() { cout << "B constructed" << endl; } static A getA() {return a;} }; int main() { B b; // A a = b.getA(); // ERROR Compiler Error: undefined reference to `B::a' static int n; cout << n << endl; // ok 0 return 0; }
定義靜態成員變量
我們在類內定義靜態成員變量時需要 static,在類外定義鏡頭成員變量時不用 static,語法如下。
class X { static int n; }; // declaration (uses 'static') int X::n = 1; // definition (does not use 'static')
這里需要注意幾點:
- const靜態成員變量無法在類內初始化
- 靜態成員變量只能在方法外定義,且一定要定義完才能對起引用。
我們考慮下為什么不能在聲明中初始化靜態變量,這是因為聲明描述來如何分配內存,但不分配內存。這里我們還是使用上面代碼的例子來說明。
using namespace std; class A { public: int x; A() { cout << "A's constructor called " << endl; } }; class B { static A a; public: B() { cout << "B's constructor called " << endl; } static A getA() { return a; } }; A B::a; // definition of a int main() { B b1, b2, b3; A a = b1.getA(); cout << a.x << endl; // 0 return 0; }
output
A's constructor called B's constructor called B's constructor called B's constructor called 0
從上述結果我們也可以看出來靜態成員變量確實在創建類對象之前初始化。
使用靜態成員變量
有兩種方法可以引用靜態成員變量,<類對象名>.<靜態數據成員名>
?或?<類類型名>::<靜態數據成員名>
To refer to a static member m of class T, two forms may be used: qualified name T::m or member access expression E.m or E->m, where E is an expression that evaluates to T or T* respectively. When in the same class scope, the qualification is unnecessary:
struct X { static void f(); // declaration static int n; // declaration }; X g() { return X(); } // some function returning X void f() { X::f(); // X::f is a qualified name of static member function g().f(); // g().f is member access expression referring to a static member function } int X::n = 7; // definition void X::f() // definition { n = 1; // X::n is accessible as just n in this scope }
類對象共享靜態成員
靜態類成員有一個特點:無論創建了多少個對象,程序都只創建一個靜態類變量副本。也就是說,類的所有對象共享同一個靜態成員。靜態數據成員和普通數據成員一樣遵從public,protected,private訪問規則;
接下來看另一個代碼示例
#include <iostream> using namespace std; class A { public: static int x; int y; static void f() { // y++; Error invalid use of member 'y' in static member function x++; cout << "A static function, x = " << x << endl; } }; int A::x; int main() { A a; cout << "x = " << A::x << endl; cout << "x = " << a.x << endl; A::f(); a.f(); return 0; }
output
x = 0 x = 0 A static function, x = 1 A static function, x = 2
const constexpr
C++提供了多種在類中定義常量的方式,其中比較常用的有?const
,constexpr
和enum
class X { // method1 const const static int n = 1; const static int m{2}; // since C++11 const static int k; // ok // method2 enum enum {Month=12}; // method3 constexpr constexpr static int arr[] = { 1, 2, 3 }; // OK constexpr static std::complex<double> n = {1,2}; // OK constexpr static int k; // Error: constexpr static requires an initializer }; const int X::k = 3;
其中注意:
1.使用 enum 時并不會創建數據成員,即所有的對象中都不包括枚舉,另外Month知識一個符號名稱,在作用于為整個類的代碼中遇到它是,編譯器將用12來替代它。而且只能是整數。
2.使用 constexpr 來創建類常量時,一定要給其定義,不能只是聲明,而const可以只是聲明,不用給出定義。?
靜態成員函數
#include <iostream> using namespace std; class Person { public: Person() {}; Person(char *name, int age); void show(); static int getTotal(); private: static int m_total; char *m_name; int m_age; }; Person::Person(char *name, int age) : m_name(name), m_age(age) { m_total++; } void Person::show() { cout << m_name << "的年齡是" << m_age << ", 總人數是" << m_total << endl; } int Person::getTotal() { return m_total; } // 一定要先初始化 int Person::m_total = 0; int main() { Person *p1 = new Person("Alice", 18); Person *p2 = new Person("Bob", 18); p1->show(); p2->show(); int total1 = Person::getTotal(); int total2 = p1->getTotal(); cout << "total1 = " << total1 << ", total2 = " << total2 << endl; return 0; }
靜態成員函數與普通成員函數的根本區別在于:普通成員函數有 this 指針,可以訪問類中的任意成員;而靜態成員函數沒有 this 指針,只能訪問靜態成員(包括靜態成員變量和靜態成員函數)。這里要注意的是普通的成員函數也能訪問靜態成員變量。這一點上和Java中的static用法很像。
總結
原文鏈接:https://blog.csdn.net/EJoft/article/details/122926070
相關推薦
- 2022-05-13 (Qt)使用QCommandLineParser進行程序的命令行解析
- 2022-11-19 詳解C語言內核中的自旋鎖結構_C 語言
- 2022-01-27 layui中iframe彈出層事件給父級填入數據
- 2022-12-22 go語言中GoMock安裝使用詳解_Golang
- 2022-05-02 python?異常捕獲詳解流程_python
- 2023-05-06 Go語言中Slice常見陷阱與避免方法詳解_Golang
- 2022-11-04 C/C++中extern函數使用詳解_C 語言
- 2022-08-19 MapReduce讀取定長文件入庫Hive表Orc格式
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支