C 程式設計雜談之三 物件導向(續)

2021-08-26 07:22:43 字數 3266 閱讀 5154

class fighter

;

上面的類可以清楚的抽象出我們所需要表達的資料型別之一,這裡也許你已經發現了一些問題:

成員函式hit用來處理戰鬥事件,但是我們有不同的角色,fighter不可能只跟自己同樣的對手作戰,我們希望它能和任何角色戰鬥,當然,使用模板函式可以簡單的解決這個問題。另外,我們必須去實現三個不同的類,並且這些類必須都實現這些屬性和方法。即使這些問題我們都解決了,現在我們要組織兩個隊伍作戰,我們希望使用一種群體型別來描述它們,問題是我們必須針對每一種類建立相應的群體結構,當然你可以認為3個不同的型別不是很多,完全可以應付,那麼如果有一天系統公升級,你需要管理上百種型別的時候,會不會頭大呢?

在c++中,繼承就可以很好的解決這個問題,在c++中,繼承表示的是一種is-a關係,即派生類is-a基類,很多現實世界中的關係可以這樣來描述,如:dog is-a animal,dog是animal的派生(繼承),繼承產生的物件擁有父(基)物件的所有屬性和行為,如animal的所有屬性和行為在dog身上都會有相應的表現。在uml的描述中,這種關係被稱為泛化(generalization)。一般情況下,當我們需要實現一系列相似(具有一定的共性)然而有彼此不同的類別的時候,使用繼承都是很好的解決辦法,例如前面的**雖然也能夠實現我們的目標,但是顯然很難管理,下面給出使用繼承後的實現:

class actor//基類

; const char* getname();

virtual void hit(actor *actor) = 0;

bool isalive();

};

actor::actor(const char* strname,const int ihealth,const int ispeed,const int ihitpoint):

m_ihealth(ihealth),

m_ispeed(ispeed),

m_ihitpoint(ihitpoint)

bool actor::isalive()

///類fighter

class fighter :public actor

;fighter::fighter(const char* strname):

actor(strname,100,20,20)

void fighter::hit(actor *actor)

if(actor&&actor->isalive()) }

///類knight

class knight :public actor

;knight::knight(const char* strname):

actor(strname,150,20,25)

void knight::hit(actor *actor)

if(actor&&actor->isalive()) }

///類warrior

class warrior :public actor

;warrior::warrior(const char* strname):

actor(strname,150,20,25)

void warrior::hit(actor *actor)

if(actor&&actor->isalive()) }

c++為我們提供了非常優秀的繼承體系(其實這是物件導向的乙個非常重要的特徵),上面的類圖中我們可以很清楚的看到他們的關係,在繼承中,基類(有些地方也稱為超類)其實是所有派生類的共性提煉的結果,有時候在開發過程中,是先有派生類,然後再提出共性,產生基類的。

就象遺傳一樣,派生類擁有基類的所有屬性和方法,如基類actor的成員函式和成員變數在每乙個派生類中都存在,即fighter、knight和warrior中都存在,在繼承關係中還存在乙個非常重要的關鍵字protected,它提供乙個界於public和private 之間的一種可見性,與private相同的地方是對於外部來說,它不可見,與public相同的地方是對與繼承體系來說,是向下可見的(其派生出來的類可以直接使用),這裡有一點是很容易讓人迷惑的,就是派生類中基類的成員可見性。對派生類來說,如果使用public繼承,那麼從基類中繼承的所有成員的可見性不變(如果是protected繼承,降一級,public變成protected,private繼承再降),那麼對於乙個從基類繼承來的private成員來說,派生類是無法訪問的(很迷惑,是麼?),雖然派生類含有這個變數,但是這是一種間接的擁有關係,在派生類中,含有乙個基類的子物件,派生類對基類成員的訪問正是通過這個子物件進行的。在思想中,永遠不要把繼承來的成員看做是自己真正擁有的,雖然使用this可以直接"看到"它們,在派生體系中private和public與其它情況沒有任何區別,而protected在體系的內部就和public完全等同。

由於派生類擁有基類的成員,所以我們可以通過派生而簡單的"重用"我們已有的**,從而大大減少重複勞動。

關於繼承的另外乙個重要的特徵就是虛函式,虛函式是形成類的多型的基礎,在上面的類中:

void knight::hit(actor *actor)

比如下面的偽碼:

actor* pa;

knight* pknight = new knight;

pa = pknight;

pa->hit(…);

這裡pa是乙個基類的指標,而它指向的是乙個派生類knight的指標,呼叫它應該是怎麼樣的情況呢?答案是hit會呼叫knight的方法,而不是基類的,因為它是乙個虛函式,虛函式的特點是它永遠忠實與實際的物件(前提是正確的使用),通過這種多型的特性,我們可以使用基類來對派生類進行正確的操作,這就解決了乙個上面的問題:使用一種群體型別來描述它們,所以我們可以這樣來遍歷資料,而不需要關心裡面究竟是一些什麼樣的資料:

vector troop1;

vector troop2;

vector::iterator it_tp1 = troop1.begin();

vector::iterator it_tp2 = troop2.begin();

while( (it_tp1!=troop1.end()) && (it_tp2!=troop2.end()) )

it_tp1++;

}

物件導向思想中的繼承是非常重要的概念,正確的運用它,會為軟體的開發過程帶來很多便利,同時,com的核心技術是使用了多重繼承來實現的。同時,繼承也是物件導向的思想中較難理解的乙個概念,這片文章我只能大致的講述其運用,而真正的融會貫通還需要長時間的學習和實踐。

下面我們給出上面的例子的完整**,這段**完成了隨機建立兩個隊伍,並進行戰鬥,直到有乙個隊伍全軍覆沒,最後輸出結果。

C 程式設計雜談之三 物件導向(續)

c 程式設計雜談之三 物件導向 續 xulion class fighter 上面的類可以清楚的抽象出我們所需要表達的資料型別之一,這裡也許你已經發現了一些問題 成員函式hit用來處理戰鬥事件,但是我們有不同的角色,fighter不可能只跟自己同樣的對手作戰,我們希望它能和任何角色戰鬥,當然,使用模...

十三 物件導向程式設計

1 物件導向基本概念 物件導向的意義在於 類和物件是物件導向中的兩個基本概念 乙個類可以有很多物件,而乙個物件必然屬於某個類 類之間的基本關係 組合 繼承是單向的,子類繼承父類所有的屬性和行為 include struct biology struct animal biology struct p...

實驗三 物件導向初步

1 實驗目的 1 學習如何宣告和編寫類的 2 學習如何編寫改變類的屬性的成員函式。3 學習如何宣告和建立物件,如何通過物件呼叫類的成員函式。2 實驗內容 2.1 設計point類 40分 1 問題描述 計算機的顯示屏的座標系是這樣的,左上角的座標為 0,0 如下圖所示。定義計算機顯示屏上的點poin...