1. 類的關係
1.1 繼承和實現:繼承表示有父子關係
1.2 依賴:(use–a),表示一個類要使用(use)另一個類。
(1)類圖
(2)三種依賴方式:函數參數或返回值、局部變量和靜態成員變量或函數
class C21 { public: //1、使用形參或返回值發生依賴關係 C22 test(C22 theC22); //2、使用局部變量發生依賴關係 void test() { C22 theC22; //或C22* theC22 = new C22; //離開這個作用域後the22要銷燬 } //3、全局變量或靜態變量(函數)發生依賴關係 void test() { C22 theC22 = g_C22; //g_C22爲全局變量 C22::func(); //使用類的靜態成員函數 } };
1.3 關聯:是一種平等的、朋友關係
(1)雙向關聯:雙方都知道對方的存在,都可以調用對方的公有成員變量和函數
①在代碼的表現爲雙方都擁有對方的一個指針或引用。注意,表現爲擁有對方的一個 “指針” 和 “引用”。
②之所以是指針和引用是有原因的。如果是值(對象)那麼就不是關聯了,而是組合。因爲是值的話,C31對象消失C32對象也會消失。這和組合的定義就一樣了 :整體與部分的關係,而且整體消失部分也會消失,部分不能獨立於整體存在。
(2)單向關聯
①表示相識關係,指C33知道C34,可以調用C34的公共成員變量和函數
②代碼上表示爲C33有C34的指針,而C34對C33一無所知。
(3)自身關聯:自己的內部有着一個指向自身的指針或引用
1.4 聚合與組合
(1)聚合:(has–a ),表示整體-部分的關係,但部分可以脫離整體而單獨存在。
①如C41聚合C42,但是C42可以離開C41而獨立存在。在創建C41類的對象時,一般不會馬上創建theC42對象,而是等待一個外界的對象傳給它。
②當用C++代碼來描繪關聯和聚合時,都是一個類包含了另外一個類的指針。但是他們是有區別的,這個區別不是C++語法上的差別,而是語義上的差別。聚合是整體和部分的關係,而且關聯是平等的朋友關係,比如。張三和李四,是關聯。而張三和張三的杯子是聚合。張三和張三的鼻子是組合。
(2)組合:Contains-a。表示整體-部分的關係,但部分不能脫離整體而單獨存在。如手腳是身體的一部分,輪胎與汽車的一部分,脫離後就沒有意義了。
①一般組合用的是值對象(如theC44,表示其生命期與整體一致)
②聚合是指針。但有時組合也可以用指針,在構造函數中創建對象,析構函數中銷燬對象。但不同的是,聚合,一般其對象指針是由類外傳入的,而組合是在類內部的構造函數中new出來的。
③從語義上看,組合與聚合也是不一樣的。當表示聚合時,部分可以脫離整體。而組合不行。
2. 依賴和聚合/組合、關聯的區別
①關聯是類之間的一種平等關係,例如老師和學生,老公和老婆,水壺裝水等就是一種關係。從語義上很容易區分出來
②組合是一種整體-部分的關係,在問題域中這種關係很明顯,從語義上可以直接分析得出。例如輪胎是車的一部分,樹葉是樹的一部分,手腳是身體的一部分這種的關係,非常明顯的整體-部分關係。
③上述的幾種關係(依賴、關聯、聚合/組合)在代碼中可能以指針、引用、值等的方式在另一個類中出現,不拘於形式,只有配合語義,結合上下文來判斷。而只給出一段代碼讓我們來判斷是什麼關係,還是無法準確判斷的。
④這裏還要說明一下,所謂的這些關係只是在某個問題域纔有效,離開了這個問題域,可能這些關係就不成立了。
3. 類關係的實例分析
(1)類圖
(2)代碼實現
//CGPSReceiver.h
#ifndef _CGPSRECEIVER_H_ #define _CGPSRECEIVER_H_ class CGPSReceiver { public: void Navigate(); }; #endif // _CGPSRECEIVER_H_
//CGPSReceiver.cpp
/////////////////////////////////////////////////////////// // CGPSReceiver.cpp // Implementation of the Class CGPSReceiver // Created on: 06-5月-2016 9:25:01 // Original author: SantaClaus /////////////////////////////////////////////////////////// #include "CGPSReceiver.h" #include <stdio.h> void CGPSReceiver::Navigate(){ printf("使用GPS導航...\n"); }
//CEngine.h
#if !defined(_CENGINE_H_) #define _CENGINE_H_ class CEngine { public: CEngine(int capacity, int power); void start(); void stop(); int getCapacity(); void setCapacity(int capacity); int getPower(); void setPower(int power); private: int mCapacity; int mPower; }; #endif //!_CENGINE_H_
//CEngine.cpp
/////////////////////////////////////////////////////////// // CEngine.cpp // Implementation of the Class CEngine // Created on: 06-5月-2016 9:25:01 // Original author: SantaClaus /////////////////////////////////////////////////////////// #include "CEngine.h" #include <stdio.h> CEngine::CEngine(int capacity, int power) { mCapacity = capacity; mPower = power; } void CEngine::start(){ printf("%d cc,%d匹馬力的發動機發動了!\n",mCapacity, mPower); } void CEngine::stop(){ printf("發動機關閉了!\n"); } int CEngine::getCapacity() { return mCapacity; } void CEngine::setCapacity(int capacity) { mCapacity = capacity; } int CEngine::getPower() { return mPower; } void CEngine::setPower(int power) { mPower = power; }
//CWheel.h
#if !defined(_CWHEEL_H_) #define _CWHEEL_H_ class CWheel { public: CWheel(int size, const char* typeName, int no); CWheel& operator = (const CWheel& cw); CWheel(const CWheel& cw); //複製構造函數 protected: int mNo; int mSize; const char* mTypeName; void check(); }; #endif // !defined(_CWHEEL_H_)
//CWheel.cpp
/////////////////////////////////////////////////////////// // CWheel.cpp // Implementation of the Class CWheel // Created on: 06-5月-2016 9:25:05 // Original author: SantaClaus /////////////////////////////////////////////////////////// #include "CWheel.h" #include <stdio.h> void CWheel::check(){ printf("檢查第%d個車輪:型號(%s),大小(%d)\n", mNo + 1, mTypeName, mSize); } CWheel::CWheel(int size, const char* name, int no){ mSize = size; mNo = no; mTypeName = name; check(); } CWheel& CWheel::operator = (const CWheel& cw) { mNo = cw.mNo; mSize = cw.mSize; mTypeName = cw.mTypeName; return *this; } CWheel::CWheel(const CWheel& cw) //複製構造函數 { mNo = cw.mNo; mSize = cw.mSize; mTypeName = cw.mTypeName; }
//CVehicle.h
#if !defined(_CVEHICLE_H_) #define _CVEHICLE_H_ #include "CWheel.h" #include <list> using namespace std; class CVehicle { protected: char* mColor; char* mMake; int mTopSpeed; list<CWheel> mWheels; //車輪與CVehicle是組合關係。聲明爲值對象 void slowDown(); void speedUp(); void start(); void stop(); }; #endif // !defined(_CVEHICLE_H_)
//CVehicle.cpp
#include "CVehicle.h" void CVehicle::slowDown(){ printf("正在減速...\n"); } void CVehicle::speedUp(){ printf("正在加速...\n"); } void CVehicle::start(){ printf("車子開始啓動\n"); } void CVehicle::stop(){ printf("車子停下\n"); }
//CBicycle.h
#if !defined(_CBICYCLE_H_) #define _CBICYCLE_H_ #include "CVehicle.h" class CBicycle : public CVehicle { public: CBicycle(); ~CBicycle(); void ride(); }; #endif // !defined(_CBICYCLE_H_)
//CBicycle.cpp
/////////////////////////////////////////////////////////// // CBicycle.cpp // Implementation of the Class CBicycle // Created on: 06-5月-2016 9:25:01 // Original author: SantaClaus /////////////////////////////////////////////////////////// #include "CBicycle.h" CBicycle::CBicycle():CVehicle(){ mColor = "白色"; mMake = "永久"; mTopSpeed = 20; printf("%s%s自行車,最高時速:%d\n", mColor, mMake, mTopSpeed); for (int i = 0; i < 2; i++) { CWheel cw(21, "B型自行車車輪", i); mWheels.push_back(cw); //會複製一份cw過去 } } CBicycle::~CBicycle(){ mWheels.clear(); } void CBicycle::ride(){ start(); speedUp(); printf("自行車行駛中...\n"); slowDown(); stop(); }
//CCar.h
#if !defined(_CCAR_H_) #define _CCAR_H_ #include "CEngine.h" #include "CGPSReceiver.h" #include "CVehicle.h" class CCar : public CVehicle { public: CCar(CGPSReceiver* gps, char* color, char* make, int topSpeed); ~CCar(); void drive(); protected: CEngine mEngine; //發動機與CCar類是組合關係,聲明爲值對象 CGPSReceiver *mGPSReceiver; //導航與CCar是聚合關係,聲明爲指針,由外部傳入 }; #endif // !defined(_CCAR_H_)
//CCar.cpp
/////////////////////////////////////////////////////////// // CCar.cpp // Implementation of the Class CCar // Created on: 06-5月-2016 9:25:01 // Original author: SantaClaus /////////////////////////////////////////////////////////// #include "CCar.h" CCar::CCar(CGPSReceiver* gps, char* color, char* make,int topSpeed) :mEngine(0, 0) { mTopSpeed = topSpeed; mEngine.setCapacity(mTopSpeed + 1000); mEngine.setPower(mTopSpeed - 70); mColor = color; mMake = make; mGPSReceiver = gps; printf("%s%s車,最高時速:%d\n", mColor, mMake, mTopSpeed); //生成4個輪子 for (int i = 0; i < 4; i++) { CWheel cw(36, "A型汽車車輪", i); mWheels.push_back(cw); //會複製一份cw過去 } } CCar::~CCar(){ mWheels.clear(); } void CCar::drive(){ if (mGPSReceiver) mGPSReceiver->Navigate(); mEngine.start(); speedUp(); printf("汽車行駛中...\n"); slowDown(); mEngine.stop(); stop(); }
//CPerson.h
#if !defined(_CPERSON_H_) #define _CPERSON_H_ #include "CGPSReceiver.h" #include "CBicycle.h" #include "CCar.h" class CPerson { public: CGPSReceiver *mGPSReceiver; //CGPSReceiver與CPerosn是關聯關係(平等、朋友關係),由類外傳入 void drive(CCar* car); //CCar與CPerson通過形參發生依賴關係 void ride(CBicycle* bicle);//CBicycle與CPerson通過形參發生依賴關係 void use(CGPSReceiver* gps);//將gps傳給mGPSReceiver; }; #endif // !defined(_CPERSON_H_)
//CPerson.cpp
/////////////////////////////////////////////////////////// // CPerson.cpp // Implementation of the Class CPerson // Created on: 06-5月-2016 9:25:04 // Original author: SantaClaus /////////////////////////////////////////////////////////// #include "CPerson.h" void CPerson::drive(CCar* car){ car->drive(); } void CPerson::ride(CBicycle* bicycle){ bicycle->ride(); } void CPerson::use(CGPSReceiver* gps){ mGPSReceiver = gps; mGPSReceiver->Navigate(); }
//main.cpp
#include <stdio.h> #include "CPerson.h" int main() { CPerson person; //GPS CGPSReceiver gps; //開車 CCar* car = new CCar(&gps, "黑色", "紅旗", 200); person.drive(car); delete car; printf("\n"); //騎自行車 CBicycle *bicycle = new CBicycle(); person.ride(bicycle); delete bicycle; printf("\n"); //測試GPS person.use(&gps); return 0; } /*輸出結果: 黑色紅旗車,最高時速:200 檢查第1個車輪:型號(A型汽車車輪),大小(36) 檢查第2個車輪:型號(A型汽車車輪),大小(36) 檢查第3個車輪:型號(A型汽車車輪),大小(36) 檢查第4個車輪:型號(A型汽車車輪),大小(36) 使用GPS導航... 1200 cc,130匹馬力的發動機發動了! 正在加速... 汽車行駛中... 正在減速... 發動機關閉了! 車子停下 白色永久自行車,最高時速:20 檢查第1個車輪:型號(B型自行車車輪),大小(21) 檢查第2個車輪:型號(B型自行車車輪),大小(21) 車子開始啓動 正在加速... 自行車行駛中... 正在減速... 車子停下 使用GPS導航... */