------------------------------------------------------(樸實的分割線)
applegame.cpp:
#include "applegame.h"
//////////////////////////////////////////////////////////////////////////
// Public
AppleGame::AppleGame()
: childList_(CHILDREN_NUM)
{
}
“看,這樣就可以了。”老C解答到。“這個是關于構造函數的一些問題,你先繼續,等程序完成了我們再來討論有關問題。”
“好的。”小P回答,然后接著寫下如下代碼。
applegame.h:
#if !defined(APPLE_GAME_H_)
#define APPLE_GAME_H_
#include "childlist.h"
class AppleGame
{
public:
AppleGame();
void play();
private:
enum {CHILDREN_NUM = 20U, KICK_OUT_NUM = 7U};
private:
bool isGameOver() const;
void doPlay();
int lastChildSeatNum() const;
private:
ChildList childList_;
};
#endif // APPLE_GAME_H_
------------------------------------------------------(樸實的分割線)
applegame.cpp:
#include "applegame.h"
#include "mydebug.h"
#include <iostream>
//////////////////////////////////////////////////////////////////////////
// Public
AppleGame::AppleGame()
: childList_(CHILDREN_NUM)
{
}
void AppleGame::play()
{
using namespace std;
MY_DEBUG("Start playing game...\n");
while (!isGameOver())
{
doPlay();
}
cout << "The last child's seat number is: " << lastChildSeatNum() << endl;
}
//////////////////////////////////////////////////////////////////////////
// Private
bool AppleGame::isGameOver() const
{
return 1 == childList_.size();
}
void AppleGame::doPlay()
{
MY_DEBUG("Playing game.\n");
childList_.countOn();
if (KICK_OUT_NUM == childList_.currNum())
{
childList_.removeCurrChild();
}
else
{
childList_.forward();
}
}
int AppleGame::lastChildSeatNum() const
{
int seatNum = childList_.lastChildNum();
return seatNum;
}
------------------------------------------------------(樸實的分割線)
childlist.h:
#if !defined(CHILD_LIST_H_)
#define CHILD_LIST_H_
class ChildList
{
public:
ChildList(int childNum);
int size() const;
void countOn();
int currNum() const;
void removeCurrChild();
void forward();
int lastChildNum() const;
};
#endif // CHILD_LIST_H_
------------------------------------------------------(樸實的分割線)
childlist.cpp:
#include "childlist.h"
#include "mydebug.h"
//////////////////////////////////////////////////////////////////////////
// Public
ChildList::ChildList( int childNum )
{
MY_DEBUG_1("Create child list of %d children.\n", childNum);
}
int ChildList::size() const
{
static int n = 10;
return --n;
}
void ChildList::countOn()
{
MY_DEBUG("Count on...\n");
}
int ChildList::currNum() const
{
static int n = 0;
return ++n;
}
void ChildList::removeCurrChild()
{
MY_DEBUG("Remove current child from child list, then move to next child.\n");
}
void ChildList::forward()
{
MY_DEBUG("Move to next child.\n");
}
int ChildList::lastChildNum() const
{
return 10;
}
“唔,照著你說的方法,我先寫applegame.cpp,感覺需要childList_提供什么接口的時候,就在childlist.h中聲明什么接
口。然后再加入childlist.cpp,簡單的實現childlist.h中聲明的接口,并加入調測代碼……編譯后修改了幾處筆誤,就是現在這個結
果。”小P揉揉手指,叫過正在天涯上灌水的老C,對他說道。
“那么你認為程序執行的結果如何?”老C問道。
“嗯,還行。起碼證明了我的算法基本上是沒有問題的。”小P回答。
“那么你就打個版本標簽吧……不明白?就是建立一個目錄然后將代碼拷貝過去。”老C心想是不是該給小P講講配置管理相關的事情了。
“哦……”小P有樣學樣的建立了一個AppleGame_V3.01的目錄,然后將所有代碼拷貝了過去。
“好吧,現在你再接著實現child list模塊吧,有問題叫我,”老C說道,“我還和朋友有一些重要的事情商量……”于是他又跑去灌水了。
老C先是灌了幾篇水文,又在起點上看了積攢起來的幾篇更新,然后又在qq上同mm聊了會天,看看表已經差不多2個小時了,扭過頭看看小P,好像還在鍵盤上敲敲打打。“如何?”他問道。
“嗯,我已經寫完了,正在檢查和調試……還根據反饋的信息修改了apple game模塊和child list模塊的某些代碼。”小P答道。
“哦?不錯不錯,比我想象的要快。”老C稱贊道,“要不我們來一起看看?”
“好!”小P應道。
applegame.cpp:
#include "applegame.h"
#include "mydebug.h"
#include <iostream>
//////////////////////////////////////////////////////////////////////////
// Public
AppleGame::AppleGame()
: childList_(CHILDREN_NUM)
{
}
void AppleGame::play()
{
using namespace std;
MY_DEBUG("Start playing game...\n");
while (!isGameOver())
{
doPlay();
}
cout << "The last child's seat number is: " << lastChildSeatNum() << endl;
cout << "Game Over! \n\n" << endl;
}
//////////////////////////////////////////////////////////////////////////
// Private
bool AppleGame::isGameOver() const
{
MY_DEBUG_1("The game has %d child now.\n", childList_.size());
return 1 == childList_.size();
}
void AppleGame::doPlay()
{
MY_DEBUG("Playing game.\n");
childList_.countOn();
if (KICK_OUT_NUM == childList_.currNum())
{
childList_.resetCountNum();
childList_.removeCurrChild();
}
else
{
childList_.forward();
}
}
int AppleGame::lastChildSeatNum() const
{
int seatNum = childList_.lastChildNum();
return seatNum;
}
------------------------------------------------------(樸實的分割線)
childlist.h:
#if !defined(CHILD_LIST_H_)
#define CHILD_LIST_H_
#include "list.h"
class ChildList
{
public:
ChildList(int childNum);
int size() const;
void countOn();
int currNum() const;
void resetCountNum();
void removeCurrChild();
void forward();
int lastChildNum() const;
private:
int currCountNum_;
List chList_;
};
#endif // CHILD_LIST_H_
------------------------------------------------------(樸實的分割線)
childlist.cpp:
#include "childlist.h"
#include "mydebug.h"
#include "list.h"
#include <cassert>
#include "list.h"
//////////////////////////////////////////////////////////////////////////
// Public
ChildList::ChildList( int childNum )
: currCountNum_(0)
{
assert(0 != childNum);
MY_DEBUG_1("Create child list of %d children.\n", childNum);
for (int i = 0; i < childNum; ++i)
{
ListNode* newNode = new ListNode;
newNode->content_.seatNum_ = i + 1;
chList_.pushBack(newNode);
}
chList_.setIndex(chList_.begin());
}
int ChildList::size() const
{
return chList_.size();
}
void ChildList::countOn()
{
++currCountNum_;
MY_DEBUG_1("Count on...Current count number is %d.\n", currCountNum_);
}
int ChildList::currNum() const
{
return currCountNum_;
}
void ChildList::resetCountNum()
{
currCountNum_ = 0;
}
void ChildList::removeCurrChild()
{
MY_DEBUG("Remove current child from child list, then move to next child.\n");
chList_.setIndex(chList_.erase(chList_.index()));
}
void ChildList::forward()
{
MY_DEBUG("Move to next child.\n");
chList_.forward();
}
int ChildList::lastChildNum() const
{
ListNode* iter = chList_.begin();
return iter->content_.seatNum_;
}
------------------------------------------------------(樸實的分割線)
list.h:
#if !defined(LIST_H_)
#define LIST_H_
struct Child
{
int seatNum_;
};
typedef Child LIST_CONTENT;
struct ListNode
{
ListNode* prev_;
ListNode* next_;
LIST_CONTENT content_;
};
class List
{
public:
List();
~List();
int size() const;
void pushBack(ListNode* newNode);
void popFront();
void setIndex(ListNode* iter);
ListNode* index() const;
ListNode* begin() const;
ListNode* end() const;
void insert(ListNode* iter, ListNode* newNode);
ListNode* erase(ListNode* iter);
void clear();
void forward();
private:
ListNode* list_;
ListNode* index_;
int size_;
};
#endif // LIST_H_
------------------------------------------------------(樸實的分割線)
list.cpp:
#include "list.h"
#include <cstring>
#include "mydebug.h"
//////////////////////////////////////////////////////////////////////////
// Public.
List::List()
: size_(0)
{
list_ = new ListNode;
list_->prev_ = list_;
list_->next_ = list_;
}
List::~List()
{
clear();
memset(list_, 0, sizeof(ListNode));
delete list_;
list_ = 0;
}
int List::size() const
{
return size_;
}
void List::pushBack( ListNode* newNode )
{
insert(end(), newNode);
}
void List::popFront()
{
if (size())
{
erase(begin());
}
}
void List::setIndex( ListNode* iter )
{
index_ = iter;
}
ListNode* List::index() const
{
return index_;
}
ListNode* List::begin() const
{
return list_->next_;
}
ListNode* List::end() const
{
return list_;
}
void List::insert( ListNode* iter, ListNode* newNode )
{
newNode->next_ = iter;
newNode->prev_ = iter->prev_;
newNode->prev_->next_ = newNode;
newNode->next_->prev_ = newNode;
++size_;
}
ListNode* List::erase( ListNode* iter )
{
MY_DEBUG_1("The node erased is %d.\n", iter->content_.seatNum_);
ListNode* it = iter->next_;
if (end() == it)
{
it = begin();
}
iter->prev_->next_ = iter->next_;
iter->next_->prev_ = iter->prev_;
memset(iter, 0, sizeof(ListNode));
delete iter;
--size_;
return it;
}
void List::clear()
{
while (size())
{
popFront();
}
}
void List::forward()
{
index_ = index_->next_;
if (end() == index_)
{
index_ = begin();
}
}
“嗯,很不錯,”老C稱贊道,“知道要使用initialize list初始化成員變量,知道要在構造函數中初始化linked list的head,還知道在析構函數中釋放內存……”老C由衷的說,“你還是知道一些編程的技巧的啊。”
“呵呵,以前本科的時候稍微學習過一些,哈哈。”小P謙虛道,“不過大部分代碼還是參考你以前C版本的實現,我只不過是改良了一小部分而已。”
“哦,不要小看改良的一小部分,如果在正確的道路上日積月累,這種變化累積起來效果還是很顯著的。”老C道,“說說你經過編碼和調試后,現在的感覺吧。”
“嗯……我就說說問題吧——好的就不說了,都是相似的——首先,感覺這種編碼方式有些繁雜,需要在幾個文件中跳來跳去的;其次,我在編寫list模塊的時
候感覺index是個很煩人的東西,恨不得將它變為public的……目前的體會也就這么多。”小P一邊想一邊說道,“噢,對了,還有關于list,怎么
樣才可以寫好這個類呢?”小P又補充道。
“你體會的挺深刻的啊,”老C點點頭,“你說的沒有錯,如果照這種方式寫代碼的確有些繁雜,因為這個工作不應當直接在編碼過程中進行,而應當在設計過程中
進行。要解決這個問題,需要引入新的工具——UML……等會再給你解釋什么是UML……”制止住小P的發問,老C接著說,“確實,將index放在
list內部會造成種種不便,但是也有解決之道,比較經典的做法是將index從list中拿出來單獨成為一個模塊或class,這就是iterator
設計模式,我們以后再慢慢說……”他停頓了一下,“至于怎么良好的設計list,也有一些經驗可以總結,同時也有一些業內的慣用法,這個我們接下來會更早
討論這個問題。”
“噢?那么我應當先學習什么呢?”小P問。
“嗯,先接觸一下UML,”老C想想說道,“然后我給你講講一些關于線性表的慣用法或者習語。最后我們再來討論如何將index與它的操作從list中拿出來。”
“好哩。”小P高興的說道。
“呵呵,現在我們終于有了一個用C++實現的穩定版本,我們就叫它4.0吧。”老C建議。
“好啊。”小P同意,于是他建立了一個AppleGame_V4.0的目錄,將所有代碼拷貝進去。
“現在我們進入到C++編程學習的階段,”老C道,“你要試著從C過渡到C++,在轉換過程中有一些細節上的事情需要注意一下。”
“哦?哪些事情?”小P問。
“包括以const、enum和inline替換#define,盡量使用const等等細節,我強烈建議你看看《Effective
C++ Third
Edition》的第一章,里面有很詳細的介紹,不過在此之前我根據我們的代碼簡單的提示一下。”老C回答道,“這本書后面的章節可能有些深入,如果你不
想看也無所謂,反正還不是時候。”他又補充了一句。
“好,我仔細研究一下那個什么書……”小P回答。
“囧。”決定無視這個什么都不知道的小正太的天真問題,老C直接指著代碼問道,“你知道這聲明最后的const是什么含義嗎?”
class AppleGame
{
public:
AppleGame();
void play();
private:
enum {CHILDREN_NUM = 20U, KICK_OUT_NUM = 7U};
private:
bool isGameOver() const;
void doPlay();
int lastChildSeatNum() const;
private:
ChildList childList_;
};
“因為isGameOver()函數沒有對AppleGame類中的任何數據進行操作,所以將它聲明為const,怎么?有什么問題嗎?”
“沒有,我只是想和你詳細討論一下。在這isGameOver()被聲明為const是很好的,但是我想說明一下背后發生了什么。”老C又拉過白板,指揮小P在上面擦出一塊空白區域,然后寫下幾行文字。
C++:
class AppleGame
{
public:
...
private:
bool isGameOver() const;
...
};
“呵呵,在這里寫這段代碼是想提醒你盡量使用const,并且要確保const的正確性,因為不聲明為const,就是你認為不需要const。”老C接著問道,“你可以簡單的解釋一下const嗎?”