山之石
----私有派生
它山之石,可以攻玉。說的是善於利用事物,可以做到自己不能做的事。
我曾經在《白馬非馬----繼承》中論及類的關係,其中說了很多公有派生的話題,指出共有派生中,子類與父類的關係為是乙個的關係,現在我要說的私有派生卻是用乙個的關係。改變了乙個關鍵字,會帶來本質的變化,這正是世事變化無常的明證。
我們先來看看,私有派生到底有什麼區別
這是乙個封裝好的類
class a;
class b : private a;
class c : public a;
void function1( a a )
void main()
我們編譯一下,會發現
b.data = 0;
function1( b );
這兩句被拒絕了,而
c.data = 0;
function1( c );
卻沒有問題
b.data = 0;
c.data = 0;
說明了私有派生與公有派生的第乙個區別,私有派生的子類所有基類的成員都將成為私有的,成員函式也不例外,不相信你可以試試看哦。
function1( b );
function1( c );
說明了私有派生與公有派生的第二個區別,私有派生的子類與其基類不再為是乙個的關係,所以
function1( b );
不能將引數轉化為乙個型別a的臨時變數。
但是私有派生的子類還是可以使用其基類的
public
和protected
的成員,與公有派生不同的是原來基類的介面不再為子類所有,子類擁有的只是其實現。
為什麼這樣說呢,在
c++中的問題在於,介面和實現一樣都是函式(方法)。這樣就令我們有所混淆,但是在私有派生中,這個問題將得到澄清。
class a };
class b : private a };
class c : public a };
void main()
b.dob();
c.doc();
是派生子類的介面
b.doa();
c.doa();
是子類使用基類的介面,但是
b.doa();編譯通不過,因為私有派生不能繼承基類的介面,但是他在
void dob( void )
卻使用了a::doa();因為他繼承了基類的結構和實現。
好了,類b可以使用類a的實現,但是不能象乙個類a一樣提供a的介面,也就是說,b是將a拿來用的,b使用乙個a,而b不是a。b和a的關係其實在於功能的使用方面,私有派生中子類與父類的關係為用乙個的關係。
既然思想上知道了私有派生的意義,那麼它到底有什麼用呢,到底需不需要私有派生呢。
這個很容易想到,既然私有派生是用乙個的關係,而我們上面說到子類對基類只是有實現方面的需要,也就是子類用基類做什麼事,那麼我們就知道私有派生適合什麼場合了。比如說樵夫用斧子劈柴火,那麼樵夫就應該用乙個斧子。
class axe;
class axman : private axe;
等等,有人不禁想到
class axman;
不是也可以描述這個關係嗎,對了!樵夫有乙個斧子的話,不就可以用乙個斧子了嗎,這樣的**看起來還更容易理解。用乙個的關係的確可以用有乙個的關係來替代,使用關聯中的組合的確可以替代私有派生的方案。
class axman;
這樣的關係看起來更有彈性,因為樵夫沒理由要永遠把斧子帶在身上,斧子還可以給別的樵夫用呢。
很明顯,這又是效率和彈性取捨的問題,沒有乙個完美的方案,只有適合不適合的方案。如果問題很明顯,而且不可預知性很少,那麼就用繼承,反之就用關聯。有人要說了,其實繼承和關聯的效果不是一樣嗎。
class axe;
class axman : private axe;
class axman;
應該沒有效率的差異吧。其實實際的問題不是這樣的。
相信很多人程式設計的時候都知道空類和空結構是占用資源的
class empty;
至少要占用乙個位元組,如果有位元組對齊還會更多,那麼
class axman;
中的axe axe;就會有資源占用,如果編譯器支援空基類優化的話,也就是由空類派生而來的子類中基類部分將不占用資源,那麼axe axe;的附加損失會在私有繼承中消失。
呵呵,我舉的這個例子過於特殊,而且涉及到編譯器等細節問題,其實我想說的還是那句話,沒有乙個完美的方案,只有適合不適合的方案。過於拘泥繼承和關聯的形式並不好,掌握了思想然後恰當的運用它才是主要的。
我們經常會用到的乙個資料結構就是堆疊了,堆疊是乙個先進後出的容器,那麼它需要使用乙個容器,stl中的vector是乙個容器,但stack不是乙個vector,他只是需要使用vector可以儲存的功能而已。
#include
#include
using namespace std;
class stack : private vector
void push( int value )
int pop( void )
bool empty( void ) };
void main( void )
結果是: 5
4 67 1
其中stack使用了vector中的push_back,pop_back,empty,rbegin的功能來實現了自己的push,pop,empty的介面和實現。stack使用了vector。
好了,現在我們知道了什麼是私有派生,以及該如何運用它。
C 繼承與派生(公有派生和私有派生)的概念
層次概念是計算機的重要概念。通過繼承 inheritance 的機制可對類 class 分層,提供型別 子型別的關係。c 通過類派生 class derivation 機制來支援繼承。被繼承的型別稱為基類 base class 或超類 superclass 新產生的類為派生類 derived cla...
C 的公有 保護 私有繼承派生
c 類的成員分為三種屬性分別是公有 保護 私有。三種屬性控制著成員的訪問控制許可權。首先講公有成員。公有成員是其類對外部的介面,任何外部函式都可以訪問公有資料或者函式。其次是保護成員。保護成員是非派生類的外部函式無法訪問保護資料或者函式,對於此類下的派生類可以訪問到此類的保護資料或者函式。最後將私有...
21 C C 之派生類的私有繼承
基類成員對其物件的可見性與一般類對其物件的可見性相同,公有成員可見,其他成員不可見。基類成員對派生類的可見性對派生類來說,基類的公有成員和保護成員是可見的,基類的公有成員和保護成員都作為派生類的私有成員,並且不能被這個派生類的子類所訪問 基類的私有成員是不可見的,派生類不可訪問基類中的私有成員。基類...