static, const 和 static const 變量的初始化問題


const 常量的在超出其作用域的時候會被釋放,但是 static 靜態變量在其作用域之外並沒有釋放,只是不能訪問。

static 修飾的是靜態變量,靜態函數。對於類來說,靜態成員和靜態函數是屬於整個類的,而不是屬於對象。可以通過類名來訪問,但是其作用域限制於包含它的文件中。

static 變量在類內部聲明,但是必須在類的外部進行定義和初始化。

const 常量在類內部聲明,但是定義只能在構造函數的初始化列表進行。

class A {
public:
    A(int a) : constNum(a) {}
private:
    static int staticNum;
    const int constNum;
};

int A::staticNum = 100;

從上面的代碼可以看出,const 常量的不變形只是針對與一個對象來說的,同一個類的不同對象的 const 常量的值可以不一樣。 

如果想讓 const 常量在類的所有實例對象的值都一樣,可以用 static const (const static),使用方式如下:

1 class A {
2     const static int num1; // 聲明
3     const static int num2 = 13; // 聲明和初始化
4 };
5 const int A::num1 = 12; // 定義並初始化
6 const int num2;  // 定義

上面兩種方式都可以對 const static 常量進行初始化。注意,第 3 行的代碼並沒有對 num2 進行定義,它只是進行聲明。其實這里給了值 13 也沒用進行初始化,因為變量必須在定義了以后才進行初始化。但是我們會發現很奇怪的問題,如下:

 1 class A {
 2 public:
 3     const static int num2 = 13; // 聲明和【初始化】
 4 };
 5 
 6 int main(int argc, char const *argv[])
 7 {
 8     cout << A::num2 << endl;
 9     return 0;
10 }

上面代碼的執行結果是 13,也就是說,num2 還沒有定義就可以使用了。至於 num2 只是聲明沒用定義的證明如下:

 1 class A {
 2 public:
 3     const static int num2 = 13; // 聲明和【初始化】
 4 };
 5 // const int A::num2;
 6 
 7 int main(int argc, char const *argv[])
 8 {
 9     cout << &(A::num2) << endl;
10     return 0;
11 }

在將第 5 行注釋后,編譯結果如下:

Undefined symbols for architecture x86_64:
  "A::num2", referenced from:
      _main in a-1e0f08.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
[Finished in 0.3s with exit code 1]

也就是說 num2 還沒有定義。在取消注釋后成功輸出 num2 的地址。說明在 加上  const int A::num2; 后 num2 才被定義。

 

那為什么 num2 還沒定義就可以使用了呢,其實因為 num2 是 const 常量,在生成匯編代碼的時候並不是在 num2 的地址內取值,而是直接將 num2 【初始化】的時候的那個值替換掉 num2。這也就是用指針改變 const 常量的值的時候 const 常量的字面值並沒有變化的原因。這個可以自己去看程序的匯編代碼來證明。這個可能在不同的編譯器有不同的實現,因為c++標准並沒有規定 const 要怎樣實現,不同的編譯器的實現可能不一樣。

 

另外一個要注意的地方是,在類內部進行 static const 的初始化只能針對於內置類型,比如如下是會報錯的:

class A {
public:
    const static string str = "str";
};

const string str;

所以如果不是必要,一般都是采用類外初始化的形式。那么什么情況下是必要的呢?我們看如下代碼:

//MyClass.h

class MyClass{
    public:
    static const int MyArraySize = 256;

    private:
        int MyArray[MyArraySize];
};

上面這樣是沒問題的,但是下面這樣就會報錯:

 1 //MyClass.h
 2 
 3 class MyClass{
 4     public:
 5     static const int MyArraySize;
 6     static const int MyValue;
 7 
 8     private:
 9         int MyArray[MyArraySize];
10 };
11 
12 //MyClass.cpp
13 #include "MyClass.h"
14 
15 const int MyClass::MyArraySize = 256;
16 const int MyClass::MyValue = 100;

在第 9 行,如果 MyArraySize 有初始化的話,會直接用它的值代替。但是這里找不到它的值,所以無法作為數組定義的size。這個時候用前面的方法就會好一點。

 

最后一個要注意的是,類內的 static const 常量的【初始化】必須用常量表達式,也就是說,這里的【初始化】值必須是一個能直接使用的值。所以如果此時要用函數返回值的話,函數應該是 constexpr 的,如下:

constexpr int fun() {
    return 12;
}

class A {
public:
    const static int num = fun();
};
const int A::num;

當然可以在 fun 函數里面進行一些計算操作。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM