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导航... "); }
//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匹马力的发动机发动了! ",mCapacity, mPower); } void CEngine::stop(){ printf("发动机关闭了! "); } 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) ", 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("正在减速... "); } void CVehicle::speedUp(){ printf("正在加速... "); } void CVehicle::start(){ printf("车子开始启动 "); } void CVehicle::stop(){ printf("车子停下 "); }
//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 ", 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("自行车行驶中... "); 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 ", 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("汽车行驶中... "); 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(" "); //骑自行车 CBicycle *bicycle = new CBicycle(); person.ride(bicycle); delete bicycle; printf(" "); //测试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导航... */