C++ 用模板實現List的Node基類
阿新 • • 發佈:2019-01-28
看了C++的單例模式後,啟發很大,剛好要寫一個List,就在想能不能用模板來實現List的Node節點。
在這裡直接上重點,完成後的程式碼:
#ifndef DONZ_TEMPLATE_NODE_H #define DONZ_TEMPLATE_NODE_H template<typename SubNode> class Node { public: Node():last(nullptr), next(nullptr) { } ~Node(){} public: const SubNode * getLast(); const SubNode * getNext(); void setLast(SubNode* setLast); void setNext(SubNode* setNext); protected: SubNode *last; SubNode *next; }; template<typename SubNode> const SubNode *Node<SubNode>::getLast() { return last; } template<typename SubNode> const SubNode *Node<SubNode>::getNext() { return next; } template<typename SubNode> void Node<SubNode>::setLast(SubNode *const _last) { last = _last; } template<typename SubNode> void Node<SubNode>::setNext(SubNode *const _next) { next = _next; //_next -> setLast(this); 這條語句是不合法的,因為this指標並不能轉化為子類指標。 //因為在基類中的this,僅程式碼基類自己,而不代表子類。 } #endif
程式碼還是很好懂的,下面的測試檔案:
#include"Node.h"
class A: public Node<A>
{
};
int main()
{
A a;
A b;
a.setNext(&b);
a.setLast(&b);
b.setNext(&a);
b.setLast(&a);
const A *c = a.getLast();
return 0;
}
優缺點比較:優點在於,省去了定義節點類的麻煩,省去了有關next last指標及相關程式碼,但有一點問題在於,如果是正常定義一個節點類,那麼成員函式setNext()我會這樣寫:
void Node::setNext(const Node *_next)
{
next = _next;
_next->setLast(this);
}
別小看這一行程式碼,這一行程式碼可以幫我們省下很多東西:
//如果a指向一個連結串列中的元素,此時如果你想把a指向的Node從連結串列中移除,那麼你需要:
a->getLast()->setNext(a->getNext());
a->getNext()->setLast(a->getLast());
發現問題了嗎?程式碼量翻倍了,如果我們能在setNext成員函式中加上一行程式碼,那麼之後每一次我們設定next節點時都可以少寫一行程式碼,反之,我們只能像上面這樣多寫一行程式碼。別小看這一行,一個大專案中,如果要多次設定next,那麼程式碼會變得很多。而且這兩行程式碼是很容易寫錯的,因為都有set get Last Next這樣的字元,一不小心極易出錯。
要解決這個問題,可能還要寫一個管理類的模板,這樣,讓寫兩行差不多程式碼這樣的工作只做一次,其它類只要使用或繼承這個模板即可(當然這只是一個設想,尚未實現出來;) ) 。
一般來說,如果不使用模板,那麼Node基類會有很大的限制,甚至幾乎不能用,因為你使用getNext或getLast得到的都是父類的指標,當然,你可以對它進行轉換,但轉換是C++中不推薦的一種做法。
而使用模板後,我們可以直接通過基類的函式得到子類的指標。多high哦 ;)
然而我不確定這種程式碼是好還是不好,看起來它帶來了便利,但實際上在父類中使用子類可能會帶來問題。不過對於這種Node,可能沒什麼影響吧,姑妄用之。