我對C++中虛擬函式、純虛擬函式在實現多型中作用的一點淺薄認識 (轉)

gugu99發表於2008-04-27
我對C++中虛擬函式、純虛擬函式在實現多型中作用的一點淺薄認識 (轉)[@more@]

 

多型是面向設計和麵向過程程式設計的主要區別之一,何謂多型?記得在CSDN裡一篇論C++多型的文章裡有一名話:“龍生九子,子子不同”多型就是同一個處理手段可以用來處理多種不同的情況,在錢能老師的《C++程式設計教程》書中有這樣一個例子:
定義了一個小學生類
[本文全部程式碼均用偽碼]
class Student
{public:
 Student(){}
~Student(){}
 void 交學費(){}
//......
};
裡面有一個 “交學費”的處理,因為大學生和小學生一些情況類似,我們從小學生類中派生出大學生類:
class AcadStudent:public Student
{public:
 AcadStudent(){}
~ AcadStudent(){}
 void 交學費(){}

//.......
};

我們知道,中學生交費和大學生交費情況是不同的,所以雖然我們在大學生中繼承了中學生的"交學費"操作,但我們不用,把它過載,定義大學生自己的交學費操作,這樣當我們定義了一個小學生,一個大學生後:

Student A;
AcadStudent B;

A.交學費(); 即小學生的,B.交學費();是呼叫大學生的,功能是實現了,但是你要意識到,可能情況不僅這兩種,可能N種如:小學生、初中生、高中生、研究生.....
它們都可以以Student[小學生類]為基類。

如果要求你在一群這樣的學生中,隨便抽出一位交納學費,你怎麼做?

:
 //A為抽出來的要交學費的同學
  {switch(typeof(A))
  {case 小學生:A.小學生:: 交學費 ();break;
  case  初中生:A.初學生:: 交學費 ();break;
  case  高中生:A.高學生:: 交學費 ();break;

  default: 
  ............. 
  }
}

首先,我們要在每個類中定義一個 typeof()用來識別它的型別,然後還要在程式中進行區別,這樣一來,雖然也行,但是,如果再增加型別則要改動switch,又走了程式導向的老路,而且想透過一個模組進行操作實現起來也有難度。
所以C++中提供了多型,即能透過遲後聯編的技術實現動態的區分。
在基類的"交學費"前加個Virtual 用來告訴系統,遇到這個處理過程要等到時再確定到底呼叫哪個類的處理過程。這樣一來就可以:

  void 通用的交學費操作 (Student &A)
{A.交學費();
}

一下全部搞定,你再加新的型別我也不怕!!![具體的實現原理參考:《Ins The C++ Model》]。如果沒有 virtual這一宣告,那麼,系統在執行前就確定了操作,比如把“大學生”傳給 
void 通用的交學費操作 (Student &A)
{A.交學費();
}
,則A.交學費();呼叫的是大學生類中繼承於Student類中的“交學費操作”
所以虛擬函式對多型的實現是必要的。

為什麼會出現純虛擬函式呢?

如果按上面的例子進行,所有型別都繼承小學生類,我們會發現一此小學生自己特定的東東[比如  void 上美術課();],也都被大學生繼承來了,雖然不影響大學生的操作,但是隨時間的加長,小學生類中自已所特定的東東越來越多,這樣下去,大學生中冗餘的資料就多了,有什麼辦法可以解決????

就是定義基類時定義一個抽象類,如學生類,在學生類中實現一此大家都有的操作
。這個過程就叫分解。
這個類子對純虛擬函式的說明還不夠明顯,換個例子比如:

 

class  人()
{public :
 //......
 void 吃()
  {人吃飯;
  }
 //......
 char *Name;
 int age;
};

class  狗()
{public :
 //......
 void 吃()
  {狗吃屎;
  }
 //......
 char *Name;
 int age;
};

人類、狗類有一些相同的東東,如名字,年紀,吃的動作等,有人想到了為了程式碼的重用,讓人類繼承狗類,可是資料的冗餘讓這個想法完蛋了,所以有人又想出可不可以定義一個這樣的類:


這個類界於人類狗類之間,有人類和狗類共有的一些東東,比如年紀,名字,體重什麼的,但它是不存在例項的,它的存在意義也是隻是為了派生其它類,如人類、狗類,這樣可以使系統清淅、。。。。。、、反正好處多多。

在這個世界上根本不存在界於人狗之間的東東,所以這個“人狗之間類”中的“吃”也是沒什麼意義,你也很難為它的內容下個定義,況且也沒必要,所以定義它為純虛擬函式,形式為:virtual void 吃()=0; 用來告訴系統:
1、這個函式可以沒有函式定義;
2、擁有本函式的類是抽象類;
你可能會說,即然純虛擬函式沒什麼意義,為什麼還要它,它的作用是什麼呢?
為實現多型作準備!!!

由於抽象類的例項沒意義,所以C++中不允許定義它的例項。(如果定義了這樣的例項A,那麼你呼叫A.吃()怎麼辦?)


當然了,你也可以在基類中,virtual 吃(){}
這樣一來,基類就不是抽象類了,可以有例項,而且對於其它方面都不影響。

但你也要承認這樣的物件是沒有什麼意識的,它的存在只能使你思考上增加負擔,除錯時還要考慮到是不是有這樣類的物件在作怪,所以C++乾脆提供了“虛擬函式”、抽象類,的機制,給我們操作時加了限制也可以認為是保險[不可以有抽象類的物件],試想當程式碼變得非常之龐大時,它的存在是多麼有必要啊!!!

 

 

小弟的一點濁見,各位大俠見笑了。

可以:
:mahongxi@hot.com大家共同討論。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10748419/viewspace-1003047/,如需轉載,請註明出處,否則將追究法律責任。

相關文章