------------------------------------------------------(朴实的分割线)
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吗?”