在前兩篇的主程式中,透過 class myData object1 物件的 object1.add(d) 來加入資料,再呼叫 common_divisor(object1.data,object1.len) 來找出答案,由於 common_divisor 並不包含在 class myData 中,所以開發人員需要了解 class myData 的資料結構及 common_divisor 的參數型態才能把兩者搭配在一起,這樣會增加程式開發的複雜度,雖然把 common_divisor 放進 class myData 中可以改善這情況,但 class myData 偏向基礎資料類別,應該要讓很多不同的開發需求都能使用,如果把 common_divisor 函式加進去,那對於不需要"最大公因數"的應用來說這個函式就多餘了。
以繼承 class myData 來建立一個包含 common_divisor 的衍生類別 gcd,是可以不用重頭開發,又可避免在 class myData 添加多餘函式的方法。
C++的繼承機制有 private, protected, public 三種,不同的繼承方式會限制衍生類別對外公開父類別成員的機制,以下程式以 public 繼承來建立衍生類別 gcd:
#include <iostream>
class myData
{
//私有區段,只有class內部程式可存取
private:
int _boundary; //陣列空間上限
//保護區段,只有class內部程式和繼承的class可存取
protected:
int len; //資料總數
int *data; //用來存放所有輸入資料的記憶空間指標
//公用區段,class內外部程式均可存取
public:
myData() //建構函式,當物件產生時會自動執行
{
len=0; //資料總數歸0
_boundary=10; //邊界設為10
data=new int[_boundary]; //配置10個int記憶空間
}
~myData() //解構函式,當物件消滅時會自動執行
{
delete [] data; //釋放data記憶空間
}
void add(int d)
{
if (len>=_boundary-1) //資料滿了,增加記憶空間
{
int *newptr=new int[_boundary+10]; //動態配置比原來多10個int記憶空間
for(int i=0; i<len; i++)
newptr[i]=data[i]; //把舊資料複製到新的位置
delete [] data; //釋放舊的記憶空間
data=newptr; //資料指標指向新的位置
_boundary+=10;
}
data[len++]=d; //把參數d放在最後的位置後再把資料長度+1
}
};
class gcd : public myData //衍生類別 gcd 以 public 方式繼承 myData
{
private:
int common_divisor(int a, int b) //遞迴函式1
{
return (a%b==0) ? b : common_divisor(b,a%b); //交換位置輾轉相除
}
int common_divisor(int d[], int n) //遞迴函式2
{
if(n==1)
return d[0];
if(n==2)
return common_divisor(d[0],d[1]); //呼叫遞迴函式1
if(n>2)
return common_divisor(common_divisor(d,n/2),
common_divisor(&d[n/2],n-n/2) ); //呼叫遞迴函式2
return 0; //n小於1才會發生
}
public:
int result() { return common_divisor(data, len); }
};
int main()
{
int d;
gcd mygcd;
std::cout << "請輸入n個正整數,輸入完成請按 Ctrl-Z" << std::endl;
while ( std::cin >> d )
mygcd.add(d);
std::cout << "最大公因數=" << mygcd.result();
return 0;
}
衍生類別 class gcd 對於父類別 class myData 是以 public 的方式繼承,有權存取父類別的 protected: 和 public: 區段,但無權存取父類別的 private: 區段;而在父類別 public: 區段中的資料或函式,以 public 方式繼承的衍生類別也會將其對外界公開,所以主程式只要宣告一個 gcd 物件 mygcd,即可以 mygcd.add() 叫用父類別的函式,最後再以 mygcd.result() 叫用 class gcd 的函式 result 得到結果。
由於外界已不必直接操作 class myData 中的 len 和 data,所以把它們搬到 protected 區段以提高資料的安全性,同時也保留讓衍生類別可以存取的彈性。而置於 private 區段的資料或函式,仍然只有 class 本身有存取權限,繼承者或外部程式均無法存取。
public繼承
protected繼承
父類別 | 衍生類別 |
public | public |
protected | protected |
private | 無法存取 |
protected繼承
父類別 | 衍生類別 |
public | protected |
protected | protected |
private | 無法存取 |
private繼承
父類別 | 衍生類別 |
public | private |
protected | private |
private | 無法存取 |
沒有留言:
張貼留言