
| 實習目標 | 課堂中舉了一個 Shape-Point-Circle-Cylinder 的不適當的繼承範例, 請綜合運用繼承, 組合的語法來設計較好的程式架構 |
|---|---|
| 步驟一 |
不適當的繼承範例如下:
class Shape
{
public:
virtual float area() const { return 0.0; }
virtual float volume() const { return 0.0; }
};
class Point: public Shape
{
public:
Point(float x=0, float y=0, float z=0)
{ this->x = x; this->y = y; this->z = z; }
float getX() const { return x; }
float getY() const { return y; }
float getZ() const { return z; }
private:
float x, y, z;
};
class Circle: public Point
{
public:
Circle(float r=0., float x=0., float y=0., float z=0.)
:Point(x,y,z),radius(r){}
float area() const { return 3.141159*radius*radius; }
float getRadius() const { return radius; }
private:
float radius;
};
class Cylinder: public Circle
{
public:
Cylinder(float h=0., float r=0.,
float x=0., float y=0., float z=0.):
Circle(r,x,y,z), height(h) {}
float area() const
{ return 2*Circle::area()+height*2*3.14159*getRadius(); }
float volume() const { return Circle::area()*height; }
private:
float height;
};
void main()
{
Point point1(1,2,3), point2(4,5,6);
Circle circle(5, 2,0,-2);
Cylinder cylinder1(5, 3, 0,0,0), cylinder2(4, 2, 1,1,1);
Shape *shapes[] = {&point1, &point2, &circle,
&cylinder1, &cylinder2};
int i;
for (i=0; i<5; i++)
{
shapes[i]->display(cout);
cout << endl;
cout << " area:" << shapes[i]->area();
cout << " volume:" << shapes[i]->volume() << endl;
}
}
上面程式碼中類別的階層如下圖:
|
| 步驟二 |
我們仔細審查所要製作的這幾個類別: Point, Circle, Cylinder,
希望重新組合這幾個物件的設計,
運用比較多的重用機制來避免程式碼的重複,
但是又不至於錯用繼承的機制。
我們發現 Circle 物件中應該可以用到一個 Point 物件來表達圓心所在, Cylinder 物件中應該可以用兩個 Circle 物件來表達上底及下底兩個圓。 另外如果希望在程式中以一致的方法來處理, 儲存這些圖形物件的話, 我們可以將共通的資料與界面抽出來成為 Shape 物件, 如下圖所示:
|
| 步驟三 |
請修改類別的定義來完成上圖的架構
首先 Shape 類別的界面除了保留 area() 及 volume() 之外, 再加上 display(), 為了透過多型指標來操作 Shape 衍生類別的物件, 這些界面函式都宣告為虛擬函式 (virtual function), 同時因為這個類別為抽象的共同界面, 所以這些虛擬函式也定義為純粹的虛擬函式 (pure virtual function):
class Shape
{
public:
virtual float area() const=0;
virtual float volume() const=0;
virtual void display(ostream &os)=0;
};
雖然 area() 及 volume() 是純粹虛擬函式,
在 Shape.cpp 中我們還是可以實作 Shape::area()
以及 Shape::volume() 來容納共通的程式,
例如:
float Shape::area() const
{
return 0.0;
}
如果衍生類別需要的話也可以呼叫這個實作。
|
| 步驟四 |
其次我們實作 Point, Circle, 和 Cylinder 三個類別,
每一個類別中都需要實作 area(), volume() 和 display()
三個函式才能夠作出該類別的實體物件。
各個類別運用其它類別來重用程式碼, 並且使用委託的機制來取代步驟一中繼承的程式界面。 例如: Circle 中定義 Point 物件 m_center, Circle 的建構元函式和 display() 函式如下:
Circle::Circle(float r, float x, float y, float z)
:m_center(x,y,z), m_radius(r)
{
}
void Circle::display(ostream &os)
{
os << "Circle: radius=" << m_radius << " center:";
m_center.display(os);
}
|
| 步驟五 |
請用下面簡單的程式碼來測試相關的功能:
#include <iostream>
using namespace std;
#include "Point.h"
#include "Circle.h"
#include "Cylinder.h"
void main()
{
Point point1(1,2,3), point2(4,5,6);
Circle circle(5, 2,0,-2);
Cylinder cylinder1(5, 3, 0,0,0), cylinder2(4, 2, 1,1,1);
Shape *shapes[] = {&point1, &point2, &circle, &cylinder1, &cylinder2};
int i;
for (i=0; i<5; i++)
{
shapes[i]->display(cout);
cout << endl;
cout << " area:" << shapes[i]->area();
cout << " volume:" << shapes[i]->volume() << endl;
}
}
範例執行程式
執行結果範例:
Point: [1,2,3]
area:0 volume:0
Point: [4,5,6]
area:0 volume:0
Circle: radius=5 center:Point: [2,0,-2]
area:78.529 volume:0
Cylinder: height=5 topCircle:Circle: radius=3 center:Point: [0,0,0]
bottomCircle:Circle: radius=3 center:Point: [0,0,5]
area:150.789 volume:141.352
Cylinder: height=4 topCircle:Circle: radius=2 center:Point: [1,1,1]
bottomCircle:Circle: radius=2 center:Point: [1,1,5]
area:75.3947 volume:50.2585
|
| 步驟六 | 請助教檢查後, 將所完成的 project (去掉 debug/ 資料匣下的所有內容) 壓縮起來, 選擇 Lab14-2 上傳, 後面的實習課程可能需要使用這裡所完成的程式 |

回
C++ 物件導向程式設計課程
首頁
製作日期: 05/31/2004
by 丁培毅 (Pei-yih Ting)
E-mail: pyting@mail.ntou.edu.tw
TEL: 02 24622192x6615
海洋大學
電機資訊學院
資訊工程系
Lagoon