它山之石 私有派生

2021-04-12 20:03:43 字數 2831 閱讀 8402

山之石

----私有派生

它山之石,可以攻玉。說的是善於利用事物,可以做到自己不能做的事。

我曾經在《白馬非馬----繼承》中論及類的關係,其中說了很多公有派生的話題,指出共有派生中,子類與父類的關係為是乙個的關係,現在我要說的私有派生卻是用乙個的關係。改變了乙個關鍵字,會帶來本質的變化,這正是世事變化無常的明證。

我們先來看看,私有派生到底有什麼區別

這是乙個封裝好的類

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 之派生類的私有繼承

基類成員對其物件的可見性與一般類對其物件的可見性相同,公有成員可見,其他成員不可見。基類成員對派生類的可見性對派生類來說,基類的公有成員和保護成員是可見的,基類的公有成員和保護成員都作為派生類的私有成員,並且不能被這個派生類的子類所訪問 基類的私有成員是不可見的,派生類不可訪問基類中的私有成員。基類...