标题: C++面向对象编程原则及人类示例
作者: 叶飞虎
日期: 2017.10.12
--------------------------------------------------------------------------------
1. 概述
在 C++ 面向对象编程中,有很多开发人员无法把控类,以及应该如何编写。在编写类时
有几个原则必须遵循,这样可以使类拥有健壮性及可用性。人类示例 TPerson 描述了类的
生命力,以及类的属性、行为和事件。
面向对象编程的二个基本特征:封装和继承。
封装的目的是为了信息隐藏,并保证类数据成员的私有性和一致性,同时数据成员之间
是强耦合,而类与类之间应该弱耦合。
继承的目的是为了扩充类的多样性,多继承和多态都是继承的扩展方式,而继承会增加
类与类之间的耦合性。
2. 面向对象编程的遵循原则
a. 类的数据成员尽量放在 private 中,若要开放信息可以通过 public 属性方法操作。
b. 类属性方法分为: 读取属性和设置属性,读取属性方法名直接用属性名无需添加前缀,
而设置属性方法前面必须添加前缀 "Set" 并后跟属性名。
c. 类提供的 public 方法必须具有完备性,如:"Add" 则有 "Delete","Begin" 则有
"End","Open" 则有 "Close","Start" 则有 "Stop" 等等。
d. 类的 public 方法必须具有防御能力,保证类成员数据安全,类就像一个封闭的城池,
public 方法就像城门,为了保证城池安全必须在城门有检查,只有这样才能使城池
内事物免受破坏。
e. 类少用继承而多用聚合,通过聚合的方式封装在新的类中,让聚合的成员之间通过行
为和事件进行关联,并形成成员间的强耦合。若要继承最好使用单类继承,而且单类
继承也能够解决多类继承问题,即通过聚合新类并继承即可。
f. 若类内部存在主动向外发起动作时,应该设置事件,并通过事件方式来解决未来问题。
对象事件就是一个开放的接口,能够绑定相同类型参数和返回值的对象方法,因为无
需知道方法所属类就可以调用对象方法,具体使用可参见 TPerson 类。
3. 示例代码, 请参见 "Person.cpp"
// ======================================= // Unit : 面向对象编程的人类示例 // Version: 1.0.0.0 (build 2017.10.12) // Author : 叶飞虎 // Email : kyee_ye(at)126.com // Copyright (C) Kyee workroom // ======================================= // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /* TPerson - 人类 */ class TPerson { public: // 人的存在状态 enum TState {psNothing, // 虚无 psEnding, // 正在消亡 psComing, // 正在孕育 psLiving}; // 活着 // 性别 enum TSex {sexUnknown, // 未知 sexFemale, // 女性 sexMale, // 男性 sexNeuter, // 中性 sexF2Male, // 女变性男 sexM2Female}; // 男变性女 // 其他类别 // ??? ... ... public: // OnSound 事件 typedef void (TObject::*TDoSound)(void* Sender, const TAudio& ASound); typedef struct { TDoSound Method; void* Object; } TOnSound; // OnView 事件 typedef void (TObject::*TDoView)(void* Sender, const TAction& AView); typedef struct { TDoView Method; void* Object; } TOnView; // 其他事件 // ??? ... ... public: TPerson(); virtual ~TPerson(); // 属性 TState State() const { return FState; } bool Living() const { return FState == psLiving; } TDateTime Birthday() const { return FBirthday; } TDateTime Deathday() const { return FDeathday; } THeadInfo HeadInfo(); // 如: 头发、五官信息等等 TBodyInfo BodyInfo(); // 如: 三围信息等等 TLimbInfo LimbInfo(); // 如: 上、下肢信息等等 // ??? ... ... bool CanProcreate() const // 是否能生育只是从性别上判断 { return (FSex == sexFemale) || (FSex == sexMale); } TSex Sex() const { return FSex; } // 性别 KYString Name() const { return FSocialInfo.Name(); } KYString CertID() const { return FSocialInfo.CertID(); } TSocialInfo& SocialInfo() { return FSocialInfo; } // ??? ... ... TPerson* Father() const { return FFather; } TPerson* Mother() const { return FMother; } long MateCount() const { return FMates.Count(); } TPerson* Mate(long AIndex) const { return (TPerson*)FMates[AIndex]; } long ChildCount() const { return FChildren.Count(); } TPerson* Child(long AIndex) const { return (TPerson*)FChildren[AIndex]; } // 设置属性 bool SetName(const KYString& AName) // 设置姓名 { return FSocialInfo.SetName(AName); } bool SetCertID(const KYString& ACertID) // 设置身份标识 { return FSocialInfo.SetCertID(ACertID); } // ??? ... ... // 设置事件 bool SetOnSound(void* AObject, TDoSound ADoSound); bool SetOnView(void* AObject, TDoView ADoView); // ??? ... ... // 生命的开始/结束 bool Begin(TPerson* AFather, TPerson* AMother); void End(bool ANeedWait); // 呼吸/喝/吃 void Breathe(const TGas& AGas); void Drink(const TLiquid& ALiquid); void Eat(const TSolid& ASolid); // ??? ... ... // 听到声音/看到景象/躯体感受外部信息.. void Listen(void* Sender, const TAudio& ASound); void See(void* Sender, const TAction& AView); // ??? ... ... // 结婚/生子 void Marry(TPerson* AMate); TPerson* MakeChild(TPerson* AMate); // 其他方法 // ??? ... ... protected: // 状态锁 void Lock() const { FLock.Enter(); } void Unlock() const { FLock.Leave(); } // 状态引用计数增/减 1 bool IncRefCount(); void DecRefCount() { InterlockedDecrement(&FRefCount); } // 对象次数增/减 1 long IncObjTimes() { return InterlockedIncrement(&FObjTimes); } long DecObjTimes() { return InterlockedDecrement(&FObjTimes); } // 发出声音/产生外观活动/产生性别 void DoSound(const TAudio& ASound); void DoView(const TAction& AView); void DoSex(TSex ASex); // ??? ... ... private: // 执行初始化/释放相关对象 bool DoInitObjs(); void DoFreeObjs(); // 执行开始/结束 bool DoBegin(TPerson* AFather, TPerson* AMother); void DoEnd(); // ??? ... ... private: TKYCritSect FLock; // 状态锁 TState FState; // 当前状态 long FRefCount; // 状态引用计数 long FObjTimes; // 对象引用次数 TDateTime FBirthday; // 对象出生时间 TDateTime FDeathday; // 对象消亡时间 // 对象的内在实体对象: 内在对象之间强耦合, 并通过血管和神经元关联, 而 DNA 直 // 接控制实体对象的变化, 产生物种的相似性和多样性。 // 注: 当对象消亡时, 其内在实体对象也随之消亡 TDNA* FDNA; // DNA 对象 THead* FHead; // 头对象 TBody* FBody; // 躯体对象 TLimb* FLimb; // 肢体对象 // ??? ... ... // 对象社会特征 TSex FSex; // 性别 TSocialInfo FSocialInfo; // 如: 身份证号、姓名、籍贯等等 // ??? ... ... // 对象关系 TPerson* FFather; // 父亲 TPerson* FMother; // 母亲 TKYList FMates; // 配偶列表 TKYList FChildren; // 孩子列表 // 事件 TOnSound FOnSound; // 发出声音事件, 如: 说话、鼓掌等等 TOnView FOnView; // 行为展示事件, 如: 跳舞等等 // ??? ... ... public: // 对象引用计数增/减 1(注: APerson 对象必须存在) static long _IncRefPerson(TPerson* APerson) { return APerson->IncObjTimes(); } static void _DecRefPerson(TPerson* APerson) { if (APerson->DecObjTimes() == 0) delete APerson; } }; // ---------------- 构造函数和析构函数 ---------------- // 构造函数 TPerson::TPerson() : FMates(true), FChildren(true) { // 初始化 FState = psNothing; FRefCount = 0; FObjTimes = 1; FBirthday = 0; FDeathday = 0; FDNA = NULL; FHead = NULL; FBody = NULL; FLimb = NULL; // ??? ... ... FSex = sexUnknown; // ??? ... ... FFather = NULL; FMother = NULL; FOnSound.Method= NULL; FOnSound.Object= NULL; FOnView.Method = NULL; FOnView.Object = NULL; // 创建对象 // ??? ... ... } // 析构函数 TPerson::~TPerson() { // 生命结束 End(true); // 释放对象 // ??? ... ... } // ---------------- 私有函数 ---------------- // 执行初始化相关对象 bool TPerson::DoInitObjs() { // 初始化 bool result = false; // 创建 DNA 对象 FDNA = new TDNA(this); if (FDNA != NULL) { // 创建对象列表 FHead = new THead(this, FDNA); FBody = new TBody(this, FDNA); FLimb = new TLimb(this, FDNA); // 判断是否创建成功 if ((FHead != NULL) && (FBody != NULL) && (FLimb != NULL)) { // 连接各个对象之间的血管及神经元, 神经中枢在头部对象中 // ??? ... ... // 设置 FHead 对象事件 FHead->SetOnSound(&TPerson::DoSound); FHead->SetOnView(&TPerson::DoView); // ??? ... ... // 设置 FBody 对象事件 FBody->SetOnSound(&TPerson::DoSound); FBody->SetOnView(&TPerson::DoView); FBody->SetOnSex(&TPerson::DoSex); // ??? ... ... // 设置 FLimb 对象事件 FLimb->SetOnSound(&TPerson::DoSound); FLimb->SetOnView(&TPerson::DoView); // ??? ... ... // 成功 result = true; } else { FreeAndNil(FHead); FreeAndNil(FBody); FreeAndNil(FLimb); FreeAndNil(FDNA); } } // 返回结果 return result; } // 执行释放相关对象 void TPerson::DoFreeObjs() { FreeAndNil(FHead); FreeAndNil(FBody); FreeAndNil(FLimb); FreeAndNil(FDNA); } // 执行开始 bool TPerson::DoBegin(TPerson* AFather, TPerson* AMother) { // 初始化 bool result = false; // 生命只有一次 if ((FMother == NULL) && (AFather != NULL) && (AMother != NULL) && (AFather != this) && (AFather != AMother) && (AMother != this) && AFather->IncRefCount()) { if (AMother->IncRefCount()) { // 能否可以生育 if (AFather->CanProcreate() && AMother->CanProcreate() && (AFather->FSex == sexMale) && (AMother->FSex == sexFemale) && DoInitObjs()) { // 父母对象 FFather = AFather; FMother = AMother; // DNA 继承自父母, 并孕育生命 if (FDNA->Inherit(FFather->FDNA, FMother->FDNA) && DoGestate()) { FBirthday = Now(); result = true; } else DoFreeObjs(); } // 引用计数减 1 AMother->DecRefCount(); } // 引用计数减 1 AFather->DecRefCount(); } // 返回结果 return result; } // 执行结束 void TPerson::DoEnd() { // 通知内在实体对象衰竭 FHead->Crash(); FBody->Crash(); FLimb->Crash(); // ??? ... ... // 等待引用计数为 0 while (FRefCount > 0) Sleep(8); // 消亡时间 FDeathday = Now(); // 内在实体对象结束 FHead->End(); FBody->End(); FLimb->End(); FDNA->End(); // ??? ... ... // 执行释放相关对象 DoFreeObjs(); } // ---------------- 保护函数 ---------------- // 引用计数加 1 bool TPerson::IncRefCount() { // 初始化 bool result = false; // 引用计数加 1 InterlockedIncrement(&FRefCount); if (FState == psLiving) result = true; else InterlockedDecrement(&FRefCount); // 返回结果 return result; } // 发出声音 void TPerson::DoSound(const TAudio& ASound) { // 初始化 TOnSound OnSound; OnSound.Method = NULL; // 取事件 Lock(); if (FState == psLiving) OnSound = FOnSound; Unlock(); // 激发 OnSound 事件 if (OnSound.Method != NULL) ((TObject*)OnSound.Object->*OnSound.Method)(this, ASound); } // 产生外观活动 void TPerson::DoView(const TAction& AView) { // 初始化 TOnView OnView; OnView.Method = NULL; // 取事件 Lock(); if (FState == psLiving) OnView = FOnView; Unlock(); // 激发 OnView 事件 if (OnView.Method != NULL) ((TObject*)OnView.Object->*OnView.Method)(this, AView); } // 产生性别 void TPerson::DoSex(TSex ASex) { FSex = ASex; } // ---------------- 公有函数 ---------------- // 如: 头发、五官信息等等 THeadInfo TPerson::HeadInfo() { // 初始化 THeadInfo result; // 引用计数加 1 if (IncRefCount()) { // 取头部信息 result = FHead->Info(); // 引用计数减 1 DecRefCount(); } // 返回结果 return result; } // 如: 三围信息等等 TBodyInfo TPerson::BodyInfo() { // 初始化 TBodyInfo result; // 引用计数加 1 if (IncRefCount()) { // 取躯体信息 result = FBody->Info(); // 引用计数减 1 DecRefCount(); } // 返回结果 return result; } // 如: 上、下肢信息等等 TLimbInfo TPerson::LimbInfo() { // 初始化 TLimbInfo result; // 引用计数加 1 if (IncRefCount()) { // 取肢体信息 result = FLimb->Info(); // 引用计数减 1 DecRefCount(); } // 返回结果 return result; } // 设置 OnSound 事件 bool TPerson::SetOnSound(void* AObject, TDoSound ADoSound) { // 初始化 bool result = false; // 判断状态 Lock(); if (FState == psLiving) { FOnSound.Object = AObject; FOnSound.Method = ADoSound; result = true; } Unlock(); // 返回结果 return result; } // 设置 OnView 事件 bool TPerson::SetOnView(void* AObject, TDoView ADoView) { // 初始化 bool result = false; // 判断状态 Lock(); if (FState == psLiving) { FOnView.Object = AObject; FOnView.Method = ADoView; result = true; } Unlock(); // 返回结果 return result; } // 生命的开始 bool TPerson::Begin(TPerson* AFather, TPerson* AMother) { // 初始化 bool result = false; bool boolNext = false; // 更改状态 Lock(); if (FState == psNothing) { boolNext = true; FState = psComing; } Unlock(); // 判断是否继续 if (boolNext) { // 执行开始 result = DoBegin(AFather, AMother); boolNext = false; // 更改状态 Lock(); if (FState != psComing) boolNext = true; else if (result) FState = psLiving; else FState = psNothing; Unlock(); // 判断是否需要结束 if (boolNext) { // 执行结束 if (result) { DoEnd(); result = false; } // 更改状态(不需要加锁) FState = psNothing; } } // 返回结果 return result; } // 生命的结束 void TPerson::End(bool ANeedWait) { // 初始化 bool boolNext = false; bool boolWait = false; // 更改状态 Lock(); if (FState == psLiving) { FState = psEnding; boolNext = true; } else if (FState == psComing) { FState = psEnding; boolWait = true; } else if (FState == psEnding) boolWait = ANeedWait; Unlock(); // 判断是否继续 if (boolNext) { // 执行结束 DoEnd(); // 更改状态(不需要加锁) FState = psNothing; } else if (boolWait) // 等待 End 结束 while (FState == psEnding) Sleep(8); } // 呼吸 void TPerson::Breathe(const TGas& AGas) { // 引用计数加 1 if (IncRefCount()) { // 气体进入身体 // ??? ... ... // 引用计数减 1 DecRefCount(); } } // 喝 void TPerson::Drink(const TLiquid& ALiquid) { // 引用计数加 1 if (IncRefCount()) { // 液体进入身体 // ??? ... ... // 引用计数减 1 DecRefCount(); } } // 吃 void TPerson::Eat(const TSolid& ASolid) { // 引用计数加 1 if (IncRefCount()) { // 固体进入身体 // ??? ... ... // 引用计数减 1 DecRefCount(); } } // 听到声音 void TPerson::Listen(void* Sender, const TAudio& ASound) { // 引用计数加 1 if (IncRefCount()) { // 大脑去分析声音 FHead->AnalyzeSound(Sender, ASound); // 引用计数减 1 DecRefCount(); } } // 看到景象 void TPerson::See(void* Sender, const TAction& AView) { // 引用计数加 1 if (IncRefCount()) { // 大脑去分析景象 FHead->AnalyzeView(Sender, AView); // 引用计数减 1 DecRefCount(); } } // 结婚 void TPerson::Marry(TPerson* AMate) { // 引用计数加 1 if ((AMate != NULL) && (AMate != this) && AMate->IncRefCount()) { // 引用计数加 1 if (IncRefCount()) { // 加入列表 FMates.Add(AMate); AMate->FMates.Add(this); // 引用计数减 1 DecRefCount(); } // 引用计数减 1 AMate->DecRefCount(); } } // 生子 TPerson* TPerson::MakeChild(TPerson* AMate) { // 初始化 TPerson* result = NULL; // 引用计数加 1 if ((AMate != NULL) && (AMate != this) && AMate->IncRefCount()) { // 引用计数加 1 if (AMate->CanProcreate() && IncRefCount()) { // 判断能否生育能力 if (CanProcreate() && (FSex != AMate->FSex)) { // 创建对象 TPerson* objChild = new TPerson; if (objChild != NULL) { // 父母对象 TPerson* objFather = this; TPerson* objMother = AMate; if (FSex != sexMale) { objFather = AMate; objMother = this; } // 判断生命是否孕育成功 if (objChild->Begin(objFather, objMother)) { FChildren.Add(objChild); AMate->FChildren.Add(objChild); result = objChild; } else delete objChild; } } // 引用计数减 1 DecRefCount(); } // 引用计数减 1 AMate->DecRefCount(); } // 返回结果 return result; } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /* 人类之间交互示例 */ // A 和 B 对象 TPerson A, B; { // A 和 B 二个交谈, 设置两者交互事件 A.SetOnSound(&B, (TPerson::TDoSound)&TPerson::Listen); A.SetOnView(&B, (TPerson::TDoView)&TPerson::See); B.SetOnSound(&A, (TPerson::TDoSound)&TPerson::Listen); B.SetOnView(&A, (TPerson::TDoView)&TPerson::See); // A 和 B 结婚 A.Marry(&B); // A 和 B 生子, 并取名 TPerson* objChild = A.MakeChild(&B); if (objChild != NULL) objChild->SetName("A-B-child1"); // ??? ... ... }
================================================================================