程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> 談談繼承的局限性

談談繼承的局限性

編輯:關於C語言

有一種普遍的說法是把封裝、繼承和多態並稱為面向對象的三大特征。如果你很熟悉C++並且對面向對象思想有過一些思考,那麼很可能對這個說法有過懷疑,面向對象思想在本質上認為世界是由對象構成的,和面向過程是世界觀的不同,而所謂的三大特征實際和面向對象的思想本質沒有半毛錢的關系,准確的表述應該是封裝、繼承和多態是C++相對於C的三大特征。如果你碰巧了解一點C++編譯器可能會發現封裝也好,繼承、多態也好都只是語法糖,技巧層面的東西而已,和思想無關。

以上為廢話。

 

本文主要就C++的繼承機制進行一些討論。很多C++教材在講到繼承時喜歡利用幾何上的一些概念,比如對如下的集合關系進行建模:

 

\

         在一次內部技術培訓的時候我提出這個問題,結果大家都沉默不語,於是我特意找了個新手程序員回答,他給出了我預料之中的答案:以四邊形作為基類,矩形和正方形依次繼承下來。沒人表示同意也沒人表示反對,可能所有的人第一反應得出的都是這個方案,但老鳥程序員會馬上察覺出其中的不妥,即使他給不出更好的方案。

         實際上在沒有給定需求場景的情況下你永遠無法設計出一個類,更不要說設計一組類和這些類的層次關系。很多教材都有這個毛病,上來就設計Student、Teacher而沒說要完成的功能是什麼,即使是做了許多年C++之後再回過頭來看那些例子還是暈忽忽的,何況初學者,——當然這也許僅僅是因為我自己太笨。

         我們設定兩個簡單的需求取邊長和計算面積,暫時不考慮繼承關系而分別實現三個類,那麼它們是下面這個樣子的:

	1 class Quadrangle
2 {
3 public:
4     int GetSideLength(int index);
5     int GetArea(void);
6 
7 private:
8     int m_arrSlide[4];
9 };
10 
11 class Rectangle
12 {
13 public:
14     int GetWidth(void);
15     int GetHeight(void);
16     int GetArea(void);
17 
18 private:
19     int m_nWidth;
20     int m_nHeight;
21 };
22 
23 class Square
24 {
25 public:
26     int GetWidth(void);
27     int GetArea(void);
28 
29 private:
30     int m_nWidth;
31 };

顯然,正方形四邊形Square 的實現最簡單,四邊形Quadrangle的實現最復雜(知道四條邊長能確定唯一的四邊形嗎?)。繼承機制有一個特點:派生類總是比基類更復雜,因為派生類是在完整的繼承了基類實現的基礎上增加新的成員、方法。由四邊形到矩形再到正方形卻是越來越簡單,這就形成了一個悖論,導致我們無法按照繼承的層次描述三者的關系。

一個老到的程序員會告訴你最好分別實現三個類,不考慮三個者之間的關系,這在大部分場景中是可行的。如果確實需要描述三者之間的層次關系,我能想到的最好的方式是使用接口:

\

 

接口用來描述層次關系,各個類獨立實現。由此也可以看出,雖然C++中的接口是用純虛類繼承實現的,但實際上接口機制和繼承機制是兩種完全不同的東西

 

到現在為止,我們可以得出結論:繼承機制實際上很難描述現實概念的層次關系,這是它的局限性對繼承的應用很多情況下並不是為了描述真實概念的層次關系,而只是組織代碼的一種形式。比如可以嘗試下用繼承關系描述一棵進化樹,你會發現這個基本上很難。

 

在C++中引入繼承機制的目的是什麼,大部分資料對此都語焉不詳,但是無論如何至少有一半的目的是為了組織和復用代碼,繼承擴展是很常用的手法,在MFC、WTL等框架中到處可以看到這樣的代碼。但是在實際的應用中一定要避免單純為了復用代碼而使用繼承機制,典型的案例比如窗口和控件。

窗口和控件是兩種完全不同的東西,微軟為了復用消息機制把兩個概念硬是揉在了一起,所有的控件都從窗口繼承下來,這直接導致了GUI框架的高復雜度和難以擴展。

代碼復用只是良好設計的副產品而不應該是設計本身的目的。

 

最後總結一下本文的核心觀點:

1.       繼承機制有很大的局限性,難於描述現實概念的層次關系;

2.       使用繼承時避免生搬硬套現實概念的層次關系;

3.       避免單純以代碼復用為目的使用繼承

微博:@飛舞的煙灰缸

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved