不必要的繼承 《C 程式設計風格》讀書筆記(四)

2021-06-17 18:42:11 字數 3841 閱讀 3883

分類: 

讀書筆記2010-02-27 08:45 

184人閱讀

收藏舉報 讀書

c++程式設計

delete

class

伺服器

如果要理解派生類和基類之間的繼承關係,那麼很重要的一點就是分別對繼承關係中的介面部分和實現部分進行分析。下面是乙個表面上非常適合使用繼承的示例,不過,在對基類和派生類的介面和實現進行了詳細的研究後,我們會對這個類的**進行大量改進。閒話少說,上**!

[cpp]view plain

copy

#include

#include

#include

class stack  

;  stack::stack (int sz)  

stack::~stack()  

void* stack::push()  

void* stack::pop()  

const

int defaultstack = 128;  

class charstack: 

public stack  

;  charstack::charstack():stack(defaultstack)  

charstack::charstack(int size):stack(size)  

charstack::charstack(int size,

char* init):stack(size)  

charstack::~charstack()  

void charstack::push(

char d)  

char charstack::pop()  

class intstack:

public stack  

;  intstack::intstack():stack(defaultstack)  

intstack::intstack(int size):stack(size)  

intstack::~intstack()  

void intstack::push(

int d)  

int intstack::pop()    

上述**的缺點:

1.       派生類中的同名函式覆蓋了基類的函式。也就是說:intstack和charstack都繼承了基類stack的公有介面,但卻用它們自身的函式把介面都隱藏起來了。

2.       在類中存在過多的指標,而只包含了少量的資訊。

3.       程式在返回值的時候過多的依賴了型別轉換,型別轉換是不安全的,應該避免使用。

改正上述缺點後的程式為:

[cpp]view plain

copy

#include

#include

class stackindex  

;  stackindex::stackindex (int sz)  

stackindex::~stackindex()  

int stackindex::push()  

int stackindex::pop()  

const

int defaultstack = 128;  

class charstack: 

public stackindex  

;  charstack::charstack() : stackindex (defaultstack)  

charstack::charstack (int size) : stackindex (size)  

charstack::charstack (int size, 

char* init) : stackindex (size)  

charstack::~charstack()  

void charstack::push (

char d)  

char charstack::pop()  

class intstack: 

public stackindex  

;  intstack::intstack() : stackindex (defaultstack)  

intstack::intstack (int size) : stackindex (size)  

intstack::~intstack()  

void intstack::push (

int d)  

int intstack::pop()    

上述**雖然更為簡單,程式的**量也更少,並且也使用了更少的記憶體,然而依然存在這不少缺陷,例如:

1. 當我們通過基類的指標或引用來使用派生類intstack或charstack的物件時,我們呼叫的將是基類的push或pop函式。

2. 與繼承相關的基類的析構函式並沒有宣告為虛函式。如果我們動態的建立了乙個intstack物件,並通過基型別的指標來刪除這個物件時,將只會呼叫基類的析構函式,從而導致記憶體洩露。

改進的方法有兩個:

1.  將stackindex作為乙個私有繼承的基類。私有繼承不但能夠防止基類的公有介面成為派生類公有介面的一部分,還能夠防止將基型別的引用或指標指向派生類物件。

2.  使用成員物件而不是繼承。關於繼承:在私有基類中,派生類繼承了所有的實現,但沒有繼承任何的介面;在公有繼承中,派生類同時繼承了基類的介面和實現;在繼承公有的抽象基類時,派生類繼承了所有的介面,但所繼承的實現可能是不完整的或者是不存在的。

在上面的例子中,派生類與其私有基類之間的關係其實類似於客戶類與伺服器類的關係。在本例中,選擇私有基類的形式與選擇成員物件的形式相比,這兩種方法功能上完全等價。但成員物件與繼承相比,語義要更加清晰,成員物件是一種更好的選擇。

注意到charstack和intstack中過載建構函式的相似性,我們應該考慮使用預設引數的形式來代替函式過載,下面是使用成員物件的完整**:

[cpp]view plain

copy

#include

#include

#include

using

namespace std;  

class stackindex  

};  

stackindex::stackindex (int sz)  

stackindex::~stackindex()  

int stackindex::push()  

int stackindex::pop()  

const

int defaultstack = 128;  

class charstack  

};  

charstack::charstack (int size, 

const

char* init) : index (size)  

charstack::~charstack()  

void charstack::push (

char d)  

char charstack::pop()  

void charstack::print()  

}  class intstack  

;  intstack::intstack (int size) : index (size)  

intstack::~intstack()  

void intstack::push (

int d)  

int intstack::pop()  

void intstack::print()  

}  int main()   

《C 程式設計風格》第三章 不必要的繼承

乙個c 類有著兩個重要的方面 用於描述類行為的公有介面,以及行為的私有實現。大多數繼承所採用的都是公有繼承的形式 派生類同時繼承了基類的藉口和實現。在私有基類中,派生類繼承了所有的實現,但沒有繼承任何介面。而在繼承公有的抽象基類時,派生類繼承了所有的介面,但所繼承的實現可能是不完整的或者是不存在的。...

C語言程式設計中避免不必要錯誤的幾點程式設計風格建議

1 定義變數的同時盡可能初始化變數 因為在c語言中變數定義後其值是不確定的,特別是指標如果不進行初始化可能無意中造成不確定記憶體的讀寫,在定義變數時盡量將其初始化,如果是變數有確定的初始值最好在定義時直接初始化,如果不確定則在定義變數時初始化為0,指標如里在初始化時沒有確定的值就初始化為null 亦...

C 程式設計規範101讀書筆記(2)設計風格

這部分主要涉及設計的風格的事宜 基本觀點還是那句話,高內聚,低耦合,擴充套件性強,簡單 第5條 乙個實體應該只用乙個緊湊的職責 一次只解決乙個問題。乙個實體只負責一件事。乙個實體職責過多,導致實體多重性格,難控制 典型反例 realloc 函式 c basic string 類 第6條 正確,簡單和...