スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

【コード】template を用いたリストクラス

長かった・・・
二週間くらい試行錯誤してたと思われる。

まずノードクラス。

template<typename T>class CNODE
{
private:
T *m_pPrev, *m_pNext;

public:
CNODE():m_pPrev(NULL), m_pNext(NULL){};

void SetPrev(T *Prev) { m_pPrev = Prev; } // 前の要素に値をセットする
void SetNext(T *Next) { m_pNext = Next; } // 次の要素に値をセットする

T* GetPrev()const { return m_pPrev; } // 前の要素へのポインタを取得
T* GetNext()const { return m_pNext; } // 次の要素へのポインタを取得
};


ノードクラスに前後を繋ぐ関数、SetPrev, SetNext を持たせました。
また、前後へのポインタを取得する関数、GetPrev, GetNext も付けときました。



次はリストクラス。

template<typename T>class CLIST
{
private:
T *m_pTop, *m_pEnd; // 先頭へのポインタ, 末尾へのポインタ
int m_NodeNum; // 要素の数

public:
CLIST():m_pTop(NULL), m_pEnd(NULL), m_NodeNum(0){}
~CLIST(){ }

//***************************************
// 指定したノードを末尾に繋げる
// 第一引数 : 追加するノード
// 戻り値 : なし
//***************************************

void PushBack(T *pAddNode)
{
if(!m_pTop) { m_pTop = pAddNode; }
if(m_pEnd) { m_pEnd->SetNext(pAddNode); }

pAddNode->SetPrev(m_pEnd);
pAddNode->SetNext(NULL);
m_pEnd = pAddNode;

++m_NodeNum;
}

//***************************************
// リストを空にする
// 引数 : なし
// 戻り値 : なし
//***************************************

void Clear()
{
T *wpNextNode = m_pTop;
T *DelNode;

while(wpNextNode)
{
DelNode = wpNextNode;
wpNextNode = DelNode->GetNext();
//SAFE_DELETE(DelNode);
}
m_NodeNum = 0;
m_pTop = m_pEnd = NULL;
}


//***************************************
// 指定したノードを削除する
// 第一引数 : 削除対象のノード
// 戻り値 : 第一引数の次のノードへのポインタ
//***************************************

T* DelNode(T *DelNode)
{
T *wpNextNode = DelNode->GetNext();

// 削除対象が先頭かどうか
if(DelNode->GetPrev()){ DelNode->GetPrev()->SetNext(wpNextNode); }
else{ m_pTop = wpNextNode; }

// 削除対象が末尾かどうか
if(wpNextNode){ DelNode->GetNext()->SetPrev(DelNode->GetPrev()); }
else { m_pEnd = DelNode->GetPrev(); }

//SAFE_DELETE(DelNode);

if(m_NodeNum>0)
m_NodeNum--;

return wpNextNode;
}

T* GetTop()const { return m_pTop; } // 先頭要素へのポインタを取得
T* GetEnd()const { return m_pEnd; } // 末尾要素へのポインタを取得
int GetNodeNum()const { return m_NodeNum; } // リストで繋がっている数を取得
};




結局循環リストにはせず、先頭・末尾へのポインタを持つことにしました。
繋がっている要素の数を数えるように m_NodeNum を変数として持たせました。

弾が出ている数でボーナスとか考えていたのでそう言う時にも使えるかもしれないし
もしかしたら使わないかもしれない。


しっかりと繋がったかを確認する必要がありますので
それも確認した結果がこちらの画像です(クリックで拡大)

template_list用:双方向リスト結果


template の理解よりも、クラス設計をどうするかで迷ってた気がする・・・
一回使っていると、また template を使う機会が出てくるに違いない。
と言う訳で、ゲーム制作から離れていましたが、非常にいい時間だったと思います。


改めまして、御津凪さん。
コードの提示・アドバイスありがとうございました!
本当に助かりました><


pre タグで囲ったものは仕切りが出来て凄く見やすい。
やっぱ移転して良かった。
ただ、コメントがしにくいw

この記事へのコメント

ちょっと質問 - Justy - 2010年06月30日 22:45:50

 一瞬どうやって使うのかわからなかったのですが、これは任意のクラス Aを CNODE<A>を継承し、CLIST<A>として使うのでしょうか?


>pre タグで囲ったものは仕切りが出来て凄く見やすい
 コピペすると……。

No title - DVDM♪管理人♪ - 2010年06月30日 23:19:28

>>Justyさん
> 一瞬どうやって使うのかわからなかったのですが
> これは任意のクラス Aを~
はい、仰るとおりです。
これではなにかまずいのでしょうか・・・。


> コピペすると……。
何か変なことがあったのでしょうか?
特段目につくような所はなかったですが・・・

【追記】
うわ・・・なんだこれ・・・。
IE でコピペすると改行されてないんですね;
FireFox なので気が付きませんでした。

No title - Justy - 2010年07月01日 00:22:10

>はい、仰るとおりです。
 なるほど、わかりました。
 ありがとうございます。


>これではなにかまずいのでしょうか・・・。
 どうやって使うのかちょっと判らなくて数分悩んだもので……。
 あー、でもまずいといえば CNODEのデストラクタが virtual指定になっていないので、使い方によっては問題が起きるかも。


>IE でコピペすると改行されてないんですね
 伝え忘れていました。そうです。IE8です。
 確かに FFとかを使えば大丈夫そうですね。

No title - DVDM♪管理人♪ - 2010年07月01日 01:06:59

> どうやって使うのかちょっと判らなくて数分悩んだもので……。
CLIST<A>, CLIST<B>, CLIST<C>・・・と、
リストを別で管理するようにしたかったのでこういう設計になりました。

使い勝手がどうかと言われると自身はないです…。
自分専用のクラスなのでなんとかなると思ってます><


> CNODEのデストラクタが virtual 指定になっていない
親クラスのデストラクタで、解放などする処理が無い場合は
デストラクタを記述していないのですが
使わなくても ~virtual CNODE(){ } としておく方がいいのでしょうか。


> 伝え忘れていました。そうです。IE8です。
> 確かに FFとかを使えば大丈夫そうですね。
まさかIEでこんな事件になるとは思ってなかったですw

No title - Justy - 2010年07月02日 23:50:46

>使わなくても ~virtual CNODE(){ } としておく方がいいのでしょうか
 あーいえ、今のところはポリモーフィズムの為の基底クラスではないので、そのままでいいと思います。
 ちょっと余計な突っ込みでしたね。すみません。

 ただ、「親クラスのデストラクタで、解放などする処理が無い場合はデストラクタを記述していない」という部分に関しては一応念の為に書いておきますと、ポリモーフィズム前提だった場合は親クラスで解放するものがなくても仮想デストラクタは必要になります。

No title - DVDM♪管理人♪ - 2010年07月04日 12:32:50

>>Justyさん
> ポリモーフィズム前提だった場合のデストラクタ
多態性を実現する必要が無いものには virtual を付けないという
自分のコーディングスタイルの一つなのですが
何もなくともとりあえず付けといたほうが安全そうではありそうですね;
うっかり付けてなくて・・・という場合は防ぎたいですね!


そもそも virtual を付けて何か困るケースとかあるんでしょうか・・・。
「何もなくてもとりあえず付けましょう」と書いているサイトは見かけますが
「virtual を付けるのは最低限にしときましょう」というのは聞いたことが無いので。

No title - Justy - 2010年07月04日 17:24:00

>virtual を付けて何か困るケース
 仮想テーブルポインタが追加される分 sizeof(クラス)が増加すること、vitualをつけたメンバ関数の呼び出しが最適化されにくいとか、そんなくらいです。

 それくらいですが環境に依ってはそこから派生していろいろ問題になることはあるでしょうね。
 オブジェクトがレジスタに載らなくなったり、CPUのキャッシュが無意味に汚れたり、アドレスオフセットに調整が必要になったり。


>「何もなくてもとりあえず付けましょう」と書いているサイト
 おっと、そんなサイトが!?
 そりゃまぁ付いていてもたいした問題にはならないので、初心者を相手にするならさほどおかしくはない話ではありますけど、やはり継承を前提としていないクラスや継承してもポリモーフィズムを使わないのであればつけるべきではない、と私は思います。

No title - DVDM♪管理人♪ - 2010年07月04日 21:55:59

>>Justyさん
> sizeof(クラス)が増加すること
> vitualをつけたメンバ関数の呼び出しが最適化されにくい~
クラスのサイズが数MBも増えるのであれば
さすがに気にしますけどそんなことはないので、サイズに関しては特に気にしてないですね~


最適化されにくいというのは初耳でした。
そうなんですか・・・。
もう一回 virtual について調べてみる必要がありそうですw


> おっと、そんなサイトが!?
「継承する可能性がなくても付けておけば大丈夫」や、
「いずれ継承するのであれば・・・」みたいな感じで書かれていました。

色々なサイトを見て回ってた時のことなので
どこのサイト(ブログ)かは忘れましたが、何件か発見して
「お~なるほど」と思い、クラスのメンバ関数全てに virtual を付けていた時期もありました。

多態性について全く知らない時に見てしまったもので
オーバーライドを勉強した時、全部に付ける必要ないじゃん・・・
ということで、必要そうな所に付ける用にしました。


> やはり継承を前提としていないクラスや
> 継承してもポリモーフィズムを使わないのであれば
> つけるべきではない、と私は思います。
virtual が付いていると継承先で別の挙動をさせてもいいのかな
あるいは、させる必要があるのかなと思ってしまうので
私もなるべく付けないでいい場合は付けない様にはしています。

トラックバック

URL :

検索フォーム
プロフィール

DVDM

Author:DVDM
自作ゲームの開発過程ブログ。
赤髪愛なら誰にも負けない。

 
Pixiv バナー


ブロとも申請フォーム
最新記事
カテゴリ
最新コメント
最新トラックバック
RSSリンクの表示
リンク
ブロとも一覧
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。