相信很多开发者在游戏开发中都会用到List表,用于存储数据或者对象。估计也有很多人对它的实现并不清楚,只是会用而已。学习知识不能仅限于表面,如果抱着只是会用,时间长了对自己的技能提升没有任何帮助不进则退,相信大家都学过侯捷先生的书,它编写的C++都是底层的实现。作为开发者来说,如果对知识的掌握只限于表面,长久下去把自己就废了。因为现在引擎都封装的非常完善,其实这样做的后果就是引擎的关键技术只是掌握在少数人手中,大部分开发者都是逻辑程序员,一直要依附于人家才能生活,这样很可悲的,作为开发者的我们更应该自己主动的去学习。这样即使引擎有问题,自己也可以轻松解决。本章主要是给读者介绍关于List的封装,List是链表,表是有结点组成的,链表的遍历可以使用迭代器实现,这些就组成了链表的封装。首先看看迭代器的定义:
/// the list iterator
class Iterator
{
public:
/// default constructor
Iterator();
/// constructor
Iterator(Node* node);
/// copy constructor
Iterator(const Iterator& rhs);
/// assignment operator
const Iterator& operator=(const Iterator& rhs);
/// equality operator
bool operator==(const Iterator& rhs) const;
/// inequality operator
bool operator!=(const Iterator& rhs) const;
/// pre-increment operator
const Iterator& operator++();
/// post-increment operator
Iterator operator++(int);
/// pre-decrement operator
const Iterator& operator--();
/// post-increment operator
Iterator operator--(int);
/// bool operator
operator bool() const;
/// safe -> operator
TYPE* operator->() const;
/// safe dereference operator
TYPE& operator*() const;
private:
friend class List<TYPE>;
/// access to node
Node* GetNode() const;
Node* node;
};
迭代器中还有Node结点指针,下面把节点Node的类定义实现如下所示:
class Node
{
friend class List;
friend class Iterator;
/// constructor
Node(const TYPE& v);
/// destructor
~Node();
/// set pointer to next node
void SetNext(Node* n);
/// get pointer to next node
Node* GetNext() const;
/// set pointer to previous node
void SetPrev(Node* p);
/// get pointer to previous node
Node* GetPrev() const;
/// get value reference
TYPE& Value();
Node* next;
Node* prev;
TYPE value;
};
链表有自己的类型,前后指针这些操作都放在链表中,整个List表的实现的完整代码如下所示:
template<class TYPE> class List
{
private:
class Node;
public:
class Iterator;
/// constructor
List();
/// copy constructor
List(const List<TYPE>& rhs);
/// destructor
~List();
/// assignment operator
void operator=(const List<TYPE>& rhs);
/// return true if the list is empty
bool IsEmpty() const;
/// get number of elements in list (slow)
SizeT Size() const;
/// clear list
void Clear();
/// add contents of other list to this list
void AddList(const List<TYPE>& l);
/// add element after given element
Iterator AddAfter(Iterator iter, const TYPE& e);
/// add element before given element
Iterator AddBefore(Iterator iter, const TYPE& e);
/// add element to beginning of list
Iterator AddFront(const TYPE& e);
/// add element to end of list
Iterator AddBack(const TYPE& e);
/// remove first element of list
TYPE RemoveFront();
/// remove last element of list
TYPE RemoveBack();
/// remove given element
TYPE Remove(Iterator iter);
/// get first element
TYPE& Front() const;
/// get last element
TYPE& Back() const;
/// get iterator to first element
Iterator Begin() const;
/// get iterator past the last element
Iterator End() const;
/// find element in array (slow)
Iterator Find(const TYPE& e, Iterator start) const;
/// the list iterator
class Iterator
{
public:
/// default constructor
Iterator();
/// constructor
Iterator(Node* node);
/// copy constructor
Iterator(const Iterator& rhs);
/// assignment operator
const Iterator& operator=(const Iterator& rhs);
/// equality operator
bool operator==(const Iterator& rhs) const;
/// inequality operator
bool operator!=(const Iterator& rhs) const;
/// pre-increment operator
const Iterator& operator++();
/// post-increment operator
Iterator operator++(int);
/// pre-decrement operator
const Iterator& operator--();
/// post-increment operator
Iterator operator--(int);
/// bool operator
operator bool() const;
/// safe -> operator
TYPE* operator->() const;
/// safe dereference operator
TYPE& operator*() const;
private:
friend class List<TYPE>;
/// access to node
Node* GetNode() const;
Node* node;
};
private:
/// a node in the list
class Node
{
friend class List;
friend class Iterator;
/// constructor
Node(const TYPE& v);
/// destructor
~Node();
/// set pointer to next node
void SetNext(Node* n);
/// get pointer to next node
Node* GetNext() const;
/// set pointer to previous node
void SetPrev(Node* p);
/// get pointer to previous node
Node* GetPrev() const;
/// get value reference
TYPE& Value();
Node* next;
Node* prev;
TYPE value;
};
Node* front;
Node* back;
};
//------------------------------------------------------------------------------
/**
*/
template<class TYPE>
List<TYPE>::Node::Node(const TYPE& val) :
next(0),
prev(0),
value(val)
{
// empty
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE>
List<TYPE>::Node::~Node()
{
#if NEBULA3_BOUNDSCHECKS
n_assert(0 == this->next);
n_assert(0 == this->prev);
#endif
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE>
void
List<TYPE>::Node::SetNext(Node* n)
{
this->next = n;
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE>
typename List<TYPE>::Node*
List<TYPE>::Node::GetNext() const
{
return this->next;
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE>
void
List<TYPE>::Node::SetPrev(Node* p)
{
this->prev = p;
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE>
typename List<TYPE>::Node*
List<TYPE>::Node::GetPrev() const
{
return this->prev;
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE>
TYPE&
List<TYPE>::Node::Value()
{
return this->value;
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE>
List<TYPE>::Iterator::Iterator() :
node(0)
{
// empty
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE>
List<TYPE>::Iterator::Iterator(Node* n) :
node(n)
{
// empty
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE>
List<TYPE>::Iterator::Iterator(const Iterator& rhs) :
node(rhs.node)
{
// empty
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE>
const typename List<TYPE>::Iterator&
List<TYPE>::Iterator::operator=(const Iterator& rhs)
{
if (&rhs != this)
{
this->node = rhs.node;
}
return *this;
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE>
bool
List<TYPE>::Iterator::operator==(const Iterator& rhs) const
{
return (this->node == rhs.node);
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE>
bool
List<TYPE>::Iterator::operator!=(const Iterator& rhs) const
{
return (this->node != rhs.node);
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE>
const typename List<TYPE>::Iterator&
List<TYPE>::Iterator::operator++()
{
#if NEBULA3_BOUNDSCHECKS
n_assert(0 != this->node);
#endif
this->node = this->node->GetNext();
return *this;
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE>
typename List<TYPE>::Iterator
List<TYPE>::Iterator::operator++(int)
{
#if NEBULA3_BOUNDSCHECKS
n_assert(0 != this->node);
#endif
Iterator temp(this->node);
this->node = this->node->GetNext();
return temp;
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE>
const typename List<TYPE>::Iterator&
List<TYPE>::Iterator::operator--()
{
#if NEBULA3_BOUNDSCHECKS
n_assert(0 != this->node);
#endif
this->node = this->node->GetPred();
return *this;
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE>
typename List<TYPE>::Iterator
List<TYPE>::Iterator::operator--(int)
{
#if NEBULA3_BOUNDSCHECKS
n_assert(0 != this->node);
#endif
Iterator temp(this->node);
this->node = this->node->GetPred();
return temp;
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE>
List<TYPE>::Iterator::operator bool() const
{
return (0 != this->node);
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE>
TYPE*
List<TYPE>::Iterator::operator->() const
{
#if NEBULA3_BOUNDSCHECKS
n_assert(this->node);
#endif
return &(this->node->Value());
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE>
TYPE&
List<TYPE>::Iterator::operator*() const
{
#if NEBULA3_BOUNDSCHECKS
n_assert(this->node);
#endif
return this->node->Value();
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE>
typename List<TYPE>::Node*
List<TYPE>::Iterator::GetNode() const
{
return this->node;
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE>
List<TYPE>::List() :
front(0),
back(0)
{
// empty
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE>
List<TYPE>::List(const List<TYPE>& rhs) :
front(0),
back(0)
{
this->AddList(rhs);
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE>
List<TYPE>::~List()
{
this->Clear();
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE>
void
List<TYPE>::operator=(const List<TYPE>& rhs)
{
this->Clear();
this->AddList();
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE>
bool
List<TYPE>::IsEmpty() const
{
return (0 == this->front);
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE>
SizeT
List<TYPE>::Size() const
{
Iterator iter;
SizeT size = 0;
for (iter = this->Begin(); iter != this->End(); iter++)
{
size++;
}
return size;
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE>
void
List<TYPE>::Clear()
{
while (this->back)
{
this->RemoveBack();
}
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE>
void
List<TYPE>::AddList(const List<TYPE>& rhs)
{
Iterator iter;
for (iter = rhs.Begin(); iter != rhs.End(); iter++)
{
this->AddBack(*iter);
}
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE>
typename List<TYPE>::Iterator
List<TYPE>::AddAfter(Iterator iter, const TYPE& e)
{
Node* node = n_new(Node(e));
if (0 == iter.GetNode())
{
#if NEBULA3_BOUNDSCHECKS
n_assert((0 == this->front) && (0 == this->back));
#endif
this->front = node;
this->back = node;
}
else
{
if (iter.GetNode() == this->back)
{
this->back = node;
}
if (0 != iter.GetNode()->GetNext())
{
iter.GetNode()->GetNext()->SetPrev(node);
}
node->SetNext(iter.GetNode()->GetNext());
iter.GetNode()->SetNext(node);
node->SetPrev(iter.GetNode());
}
return Iterator(node);
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE>
typename List<TYPE>::Iterator
List<TYPE>::AddBefore(Iterator iter, const TYPE& e)
{
Node *node = n_new(Node(e));
if (0 == iter.GetNode())
{
#if NEBULA3_BOUNDSCHECKS
n_assert((0 == this->front) && (0 == this->back));
#endif
this->front = node;
this->back = node;
}
else
{
if (iter.GetNode() == this->front)
{
this->front = node;
}
if (0 != iter.GetNode()->GetPrev())
{
iter.GetNode()->GetPrev()->SetNext(node);
}
node->SetPrev(iter.GetNode()->GetPrev());
iter.GetNode()->SetPrev(node);
node->SetNext(iter.GetNode());
}
return Iterator(node);
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE>
typename List<TYPE>::Iterator
List<TYPE>::AddFront(const TYPE& e)
{
return this->AddBefore(this->front, e);
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE>
typename List<TYPE>::Iterator
List<TYPE>::AddBack(const TYPE& e)
{
return this->AddAfter(this->back, e);
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE>
TYPE
List<TYPE>::Remove(Iterator iter)
{
#if NEBULA3_BOUNDSCHECKS
n_assert(iter.GetNode());
#endif
Node* node = iter.GetNode();
if (node->GetPrev())
{
node->GetPrev()->SetNext(node->GetNext());
}
if (node->GetNext())
{
node->GetNext()->SetPrev(node->GetPrev());
}
if (node == this->front)
{
this->front = node->GetNext();
}
if (node == this->back)
{
this->back = node->GetPrev();
}
node->SetNext(0);
node->SetPrev(0);
TYPE elm = node->Value();
n_delete(node);
return elm;
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE>
TYPE
List<TYPE>::RemoveFront()
{
#if NEBULA3_BOUNDSCHECKS
n_assert(0 != this->front);
#endif
return this->Remove(this->front);
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE>
TYPE
List<TYPE>::RemoveBack()
{
#if NEBULA3_BOUNDSCHECKS
n_assert(0 != this->back);
#endif
return this->Remove(this->back);
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE>
TYPE&
List<TYPE>::Front() const
{
#if NEBULA3_BOUNDSCHECKS
n_assert(0 != this->front);
#endif
return this->front->Value();
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE>
TYPE&
List<TYPE>::Back() const
{
#if NEBULA3_BOUNDSCHECKS
n_assert(0 != this->back);
#endif
return this->back->Value();
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE>
typename List<TYPE>::Iterator
List<TYPE>::Begin() const
{
return Iterator(this->front);
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE>
typename List<TYPE>::Iterator
List<TYPE>::End() const
{
return 0;
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE>
typename List<TYPE>::Iterator
List<TYPE>::Find(const TYPE& e, Iterator start) const
{
for (; start != this->End(); start++)
{
if (*start == e)
{
return start;
}
}
return 0;
}
学习代码是非常枯燥的,但是知道了它内部的实现原理,使用起来才会更顺手。自己尝试封装一下,再去实现某个小功能,坚持下去,对引擎也会有所了解的。