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