1. 程式人生 > >面向物件設計中private,public,protected的訪問控制原則及靜態程式碼塊的初始化順序

面向物件設計中private,public,protected的訪問控制原則及靜態程式碼塊的初始化順序

第一:private, public, protected訪問標號的訪問範圍。private:只能由         1.該類中的函式         2.其友元函式訪問不能被任何其他訪問,該類的物件也不能訪問。
protected:可以被         1.該類中的函式         2.子類的函式         3.其友元函式訪問但不能被該類的物件訪問。
public:可以被         1.該類中的函式         2.子類的函式         3.其友元函式訪問         4.該類的物件訪問。注:友元函式包括3種:     設為友元的普通的非成員函式;     設為友元的其他類的成員函式;
     設為友元類中的所有成員函式。

第二:類的繼承後方法屬性變化。
private屬性不能夠被繼承。
使用private繼承父類的protected和public屬性在子類中變為private;
使用protected繼承,父類的protected和public屬性在子類中變為protected;
使用public繼承,父類中的protected和public屬性不發生改變;
如下所示:               public:      protected:           private:
public繼承     public       protected             不可用
protected繼承  protected    protected            不可用
private繼承    private      private              不可用


protected繼承和private繼承能降低訪問許可權。

為了進一步理解三種不同的繼續方式在其成員的可見性方面的區別,下面從三種不同角度進行討論。
  對於公有繼續方式:
  (1) 基類成員對其物件的可見性:
  公有成員可見,其他不可見。這裡保護成員同於私有成員。
  (2) 基類成員對派生類的可見性:
  公有成員和保護成員可見,而私有成員不可見。這裡保護成員同於公有成員。
  (3) 基類成員對派生類物件的可見性:
  公有成員可見,其他成員不可見。
  所以,在公有繼承時,派生類的物件可以訪問基類中的公有成員;派生類的成員函式可以訪問基類中的公有成員和保護成員。這裡,一定要區分清楚派生類的物件和派生類中的成員函式對基類的訪問是不同的。
  對於私有繼續方式:

  (1) 基類成員對其物件的可見性:
  公有成員可見,其他成員不可見。
  (2) 基類成員對派生類的可見性:
  公有成員和保護成員是可見的,而私有成員是不可見的。
  (3) 基類成員對派生類物件的可見性:
  所有成員都是不可見的。
  所以,在私有繼續時,基類的成員只能由直接派生類訪問,而無法再往下繼續。
  對於保護繼續方式:
  這種繼續方式與私有繼續方式的情況相同。兩者的區別僅在於對派生類的成員而言,對基類成員有不同的可見性。
  上述所說的可見性也就是可訪問性。關於可訪問性還有另的一種說法。這種規則中,稱派生類的物件對基類訪問為水平訪問,稱派生類的派生類對基類的訪問為垂直訪問。
  一般規則如下:
  公有繼續時,水平訪問和垂直訪問對基類中的公有成員不受限制;
  私有繼續時,水平訪問和垂直訪問對基類中的公有成員也不能訪問;
  保護繼續時,對於垂直訪問同於公有繼續,對於水平訪問同於私有繼續。
  對於基類中的私有成員,只能被基類中的成員函式和友元函式所訪問,不能被其他的函式訪問。
  基類與派生類的關係
  任何一個類都可以派生出一個新類,派生類也可以再派生出新類,因此,基類和派生類是相對而言的。
  基類與派生類之間的關係可以有如下幾種描述:
  1. 派生類是基類的具體化
  類的層次通常反映了客觀世界中某種真實的模型。在這種情況下,不難看出:基類是對若干個派生類的抽象,而派生類是基類的具體化。基類抽取了它的派生類的公共特徵,而派生類通過增加行為將抽象類變為某種有用的型別。
  2. 派生類是基類定義的延續
  先定義一個抽象基類,該基類中有些操作並未實現。然後定義非抽象的派生類,實現抽象基類中定義的操作。例如,虛擬函式就屬此類情況。這時,派生類是抽象的基類的實現,即可看成是基類定義的延續。這也是派生類的一種常用方法。
  3. 派生類是基類的組合
  在多繼續時,一個派生類有多於一個的基類,這時派生類將是所有基類行為的組合。

  派生類將其本身與基類區別開來的方法是新增資料成員和成員函式。因此,繼續的機制將使得在建立新類時,只需說明新類與已有類的區別,從而大量原有的程式程式碼都可以複用,所以有人稱類是“可複用的軟體構件”

二、各個變數在類載入的時候的初始化順序

public class StaticTest{
    public static void main(String args[]){
        staticFunction();
    }
    static StaticTest st = new StaticTest();
    static{
        System.out.println("1");
    }
    StaticTest(){
        System.out.println("3");
        System.out.println("a="+a+" b="+b);
    }
    public static void staticFunction(){
        System.out.println("4");
    }
    {
        System.out.println("2");
    }
    int a=100;
    static int b=112;
}

我們先來看一下各個變數在類載入的時候的初始化順序:
1、初始化父類的靜態變數,靜態程式碼塊,初始化的順序按照出現順序。
2、初始化子類的靜態變數,靜態程式碼塊。
3、初始化父類的成員變數。
4、執行父類的建構函式。
5、初始化子類的成員變數。
6、構造程式碼塊建立物件時執行。
7、執行子類的建構函式。
執行的結果為:
2
3
a=100,b=0
1
4
產生這個結果的原因的關鍵在這一句話:
static StaticTest st = new StaticTest();

st變數的引用是本類的例項,因此在例項化st變數時,將例項初始化嵌入到靜態初始化中。因為這一句放在靜態初始化的開頭,所以static int b=112沒有被呼叫,輸出的b=0,同時,輸出1也在2和3後面。在物件的初始化時,也是先初始化環境變數,再執行建構函式,a的值為100。

靜態資料成員

假如我們要設計一個戰爭遊戲,遊戲中有許多的兵種。遊戲的過程中,每隔一段時間每個兵種都會產生,同時由於戰爭的消耗,每個兵種士兵的數量又會減少。為了情節更逼真吶,我們引入了一個士氣的概念,當士氣比較高的時候,這個兵種的士氣戰鬥力就會很強,士氣較低的時候,兵種的戰鬥力就會比較弱。兵種的士氣受很多因素影響,其中一個最直接的因素就是士兵的數量相關,它與數量成正比。我們就需要一組全域性變數,每個變數都會記錄當前兵種的數量,但是使用全域性變數會引入很多的問題,使用全域性變數的安全得不到保障,我們可以在程式的任何地方修改它的值。全域性變數還可能導致名稱空間的汙染,當程式比較大的時候,各個模組之間有可能衝突。那如果不使用全域性變數,我們就可以使用靜態的資料成員。

靜態資料成員:以static開頭。靜態資料成員為各個物件共有,不屬於某個具體的物件,所有物件都可以對它進行引用,都可以讀取和修改。若一個物件修改了該靜態成員的值,則在其他各個物件中該資料成員的值都會同時改變。

定義類時就為靜態資料成員分配空間,不隨物件的建立而分配空間。可以說它是屬於這個類的,定義完類之後就可以引用。

1.定義方法

static  int count;//定義了一個int型別的靜態資料成員,它的定義是在類裡面,但是初始化不可以在類的裡面類外面初始化 (你可以在類的實現檔案裡面初始化):
int CTime::count=0;//初始化不要再加static

2.呼叫方法

1)類名::靜態成員

2)物件名.靜態成員

在類內的靜態資料成員僅僅是對該成員的宣告,同時還需要在類外部進行定義。

當我們在建構函式裡面對它++然後輸出,在解構函式裡面—輸出就得到這樣的結果:建構函式呼叫的次數就是建立物件的個數,解構函式呼叫的次數就是銷燬物件的次數。

static1.png

靜態成員函式

在宣告成員函式時在函式前新增static關鍵字就定義了靜態成員函式。

與靜態資料成員一樣,靜態成員函式也是類的一部分。

1.宣告靜態成員函式

static int func();  //定義的時候不需要static關鍵字

2.呼叫靜態成員函式

1)類名::靜態成員函式

2)物件名.靜態成員函式

靜態成員函式一般是為了處理靜態的資料成員。

與一般成員函式的區別:

1)非靜態成員函式有this指標,靜態成員函式沒有this指標。

2)因為它可以在未定義類物件時就可以引用。因此靜態成員函式不能訪問本類中的非靜態成員(沒有this指標,就不能通過引用呼叫成員函式和資料成員)