1. 程式人生 > >《隨筆五》——C#中的 —— “ 靜態成員的生存期 、靜態成員函式、成員常量”

《隨筆五》——C#中的 —— “ 靜態成員的生存期 、靜態成員函式、成員常量”

目錄

靜態成員的生命期

靜態成員函式

成員常量

常量與靜態量


先看一個靜態欄位的示例:

namespace Ch05Ex03
{
    class Persion
    {
        int Mem1;
        static int Mem2; //私有靜態成員
        static Persion()
        {
            Mem2 = 900;
            //Mem1 = 200; //不可以在靜態建構函式中初始化 非靜態欄位
            WriteLine("靜態建構函式被呼叫!\n");
        }
        public Persion(int aa,int bb)
        {
            Mem1 = aa;
            Mem2 = bb; //利用建構函式設定私有靜態成員
            WriteLine("\n例項建構函式被呼叫!\n");
        }
        public void SetVars(int v1,int v2)
        {
            Mem1 = v1;
            Mem2 = v2;
        }
        public void Display(string str)
        {
            WriteLine($"{str}: Mem1的值:{Mem1}, Mem2的值:{Mem2}");
        }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            Persion d1 = new Persion(2, 8);  //利用公有建構函式設定靜態欄位和普通欄位的值
            d1.Display("d1");
            Persion d2 = new Persion(5, 77);
            d2.Display("d2");

            WriteLine();
            d1.SetVars(7, 22); //利用公有成員函式設定靜態欄位和普通欄位的值
            d1.Display("d1");
            
            d2.SetVars(99, 100);
            d2.Display("d2");
            d1.Display("d1"); //這裡再次輸出d1的值,輸出就是 7,100,因為它被d2 改變了

            // 注意下面的程式碼:
            Persion d3 = new Persion(141, 55), d4 = new Persion(454, 666);

            /*該程式碼輸出:
             * d3: Mem1的值:141, Mem2的值:666
              d4: Mem1的值:454, Mem2的值:666

              為什麼d3的值是141和666, 而不是141,55 呢?
              首先執行該程式碼的時候我們呼叫例項建構函式執行成員初始化,我們首先初始化例項d3的成員,然後設定
              d4的成員 ,設定d3的時候我們初始化Mem1為141,Mem2 = 55, 設定d4的值時初始化Mem1為454. Mem2 = 666.
              因為靜態欄位被類的所有例項所共享, 所有例項都訪問同一記憶體位置。因此d4把靜態欄位Mem2的值改變了,
             因此 d3的 Mem2 的值也改變了。*/
            d3.Display("d3");
            d4.Display("d4");

            ReadKey();
        }
    }
}

輸出結果為:

靜態建構函式被呼叫!

例項建構函式被呼叫!

d1: Mem1的值:2, Mem2的值:8

例項建構函式被呼叫!

d2: Mem1的值:5, Mem2的值:77

d1: Mem1的值:7, Mem2的值:22
d2: Mem1的值:99, Mem2的值:100
d1: Mem1的值:7, Mem2的值:100


例項建構函式被呼叫!

例項建構函式被呼叫!

d3: Mem1的值:141, Mem2的值:666
d4: Mem1的值:454, Mem2的值:666

那為什麼沒有輸出靜態建構函式中設定的值呢,道理都是一樣的,程式首先呼叫的就是靜態建構函式,呼叫之後  Mem2 = 900; Mem1=0; 記住: 不管這個類有多少個類例項, 靜態建構函式只調用一次。

然後就呼叫例項建構函式,例項建構函式設定的值直接覆蓋了靜態建構函式中的值,所以輸不出靜態建構函式設定的值。


靜態成員的生命期


●  只有在例項建立之後才產生例項成員,在例項銷燬後例項成員就不存在了。

● 但靜態成員,即使類沒有例項,也存在靜態成員,並且可以訪問。(在C++中不可以這樣)

namespace Ch05Ex03
{
    class D
    {
        static public int Mem2; //但是如果設定為私有的靜態成員,就不可以在類外通過類直接訪問
    }
    class Program
    {
        static void Main(string[] args)
        {
            D.Mem2 = 5; //通過類名直接為公有靜態資料成員賦值, 但是如果該成員是私有,就不可以這樣賦值
            WriteLine(D.Mem2);
            ReadKey();
        }
    }
}

輸出結果為:

5

注意: 靜態成員即使沒有類的例項也存在。如果該靜態欄位有初始化語句,那麼會在使用該類的任何靜態成員之前初始化該欄位, 但沒必要在程式執行的開始就初始化。

 


靜態成員函式


● 如同靜態欄位,靜態成員函式獨立於任何類例項。 即使沒有類的例項,仍然可以呼叫靜態方法。(C++中不可以這樣)

● 注意:類成員函式(無論是static成員函式或非static成員函式)都可以直接訪問static資料成員,static 成員函式僅能訪問static 資料成員,不能訪問非static的資料成員,也不能訪問非static 的成員函式。
 

namespace Ch05Ex03
{
    class D
    {
 
        static public int Mem2;
        public int aa = 10; //在類定義中初始化一個非靜態的公有成員
        static public void PrintVal() //靜態成員函式訪問靜態成員資料
        {
            WriteLine(Mem2);
            //WriteLine(aa); 靜態成員不可以訪問非靜態資料成員
        }
        public void getVal()
        {
            WriteLine(aa);  // 輸出aa的值
             WriteLine(Mem2); //非靜態函式可以訪問靜態的資料成員
        }
    }
  
    class Program
    {
        static void Main(string[] args)
        {
            D.Mem2 = 5;
            D.PrintVal();
 
            D dd = new D(); // 建立該類的物件
            dd.getVal(); 
            ReadKey();
        }
    }
}
 
輸出結果為:
5
10
5

在C++中可以宣告常量為靜態的常量成員資料, 而在C#中卻不可以。

與C++不同,在C#中沒有全域性常量。 每個常量都必須宣告在型別內。


成員常量


namespace Ch05Ex03
{
    class D
    {
        //用於初始化常量的值必須是在編譯時就可以確定的,通常是一個簡單型別的值或者一個表示式
        const int Mem2 = 5;
        const int Mem3 = 2 * Mem2; // 正確, 但是Mem2 必須是一個const欄位,否則錯誤。
    }
    class Program
    {
        static void Main(string[] args)
        {         
            ReadKey();
        }
    }
}

常量與靜態量


●  注意: 常量成員即使沒有類的例項也可以使用。 與真正的靜態量不同, 常量沒有自己的儲存位置, 而是在編譯時被編譯器替換。 跟C++中的 #define 類似。

看一個C++的程式:

class D
{
 
public:
	const double PI = 3.14;
	D(decltype(PI) aa):PI(aa)
	{
		
	}
};
 
int main()
{
	D dd(22.3);
	cout << dd.PI << endl;
	system("pause");
	return 0;
}

看一個C#程式:

namespace Ch05Ex03
{
    class D
    {
        public const double PI = 3.14;
       
    }
  
    class Program
    {
        static void Main(string[] args)
        {
            WriteLine(D.PI);   //利用類例項訪問公有常量資料成員
            ReadKey();
        }
    }
}

在C#中常量成欄位現得像一個靜態量 但不能將常量欄位宣告成 static:

static const double PI = 3.14; //錯誤

但是在C++中可以。