================================================================================
标题: 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"
================================================================================
标题: 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");
// ??? ... ...
}
================================================================================