忍者ブログ

神戸電子専門学校ゲームソフト学科の生徒が運営するGESのブログです。

   

[PR]

×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

インターフェイス講座

ども、こんばんわ~

目を閉じれば楽園が見えてるZAKIです

発表会はすごい作品が多かったですね~

とってもよく作りこんであったり、アイデアが面白かったりすごいチームばかりでした

僕もがんばってやらなければっ


さて、今回のテーマは「インターフェイス講座」です

C++言語のクラスについての話になるので2年生対象ですね

みなさんはインターフェイスって使ってますか?

これを使ってやると沢山のコードを使いまわせたりするんですよ

拍手[0回]



さて、C++言語でもinterfaceって書けばインターフェイスが定義できるの知ってましたか?

interface ITest {
public:
  virtual GetValue() = 0;
  virtual SetValue() = 0;
};


こんな感じでメソッドを全て純粋仮想関数にしてやれば定義できますよ

それでは、これを使うとどう、コードを使いまわせるのか。

とりあえず、例を見ながら説明しましょう

今回はXFileを読み込んだクラスのインスタンスを保存して、必要なときに取り出して使う、リソースマネージャー的なものを作るとします。

XFileの読み込みをする場合、スキンメッシュスタティックメッシュ(普通のメッシュ)の大きく2パターンがありますね。

この二つをクラスにするとして、共通する処理は

読み込み
描画
開放

の3つがありますね。

なので、これをインターフェイスで定義します。

//ロード時のデータ構造体
typedef  struct _tag_XFILE_LOADDATA {
  LPDIRECT3DDEVICE9 pd3dDevice;   
//デバイス
  string szFileName; 
//ファイル名
}XFILE_LOADDATA;


//Interface定義
interface IXFile {
public:
  //読み込み
  virtual HRESULT LoadFile(XFILE_LOADDATA *pLoadData) = 0;
  //描画
  virtual HRESULT Render(LPDIRECT3DDEVICE9 pd3dDevice) = 0;
  //開放
  virtual void Release() = 0;
};


こんな感じですかね

これをスキンメッシュクラスとスタティックメッシュクラスで実装してメソッドをオーバーライドします

LoadFile()メソッドの引数が構造体になっているのは、クラスを作っている最中に他にいるデータがあった場合、

引数で一つ一つ指定すると、継承した先のメソッドも全て変更しなければならないので面倒です。

その分構造体にしておくと、構造体のメンバを変更するだけで済むからです

ポインタで渡しているのは、インターフェイスの実装先で構造体を更に継承して、データを増やせるようにするためです

Render()メソッドの引数はデバイスだけにしているので、構造体にはしていません

今回の場合はRender()メソッドは使いませんが、一応共通するメソッドと言うことで定義しています

シェーダなどを内部に持たせる場合は他に引数がいる可能性もあるので、構造体にしてもいいでしょう

ここまでだとただめんどくさいだけですねw

さて、肝心なのはここからです。

今度はスキンメッシュクラス、スタティックメッシュクラスを読み込んで、保管しておくリソースマネージャーを作ります。

//XFILEの読み込みタイプを指定
enum XFILE_TYPE {
  XFILE_STATIC,    
//スタティックメッシュ
  XFILE_SKIN,               //スキンメッシュ
  XFILE_TYPE_NUM,  
//読み込みタイプ総数
};


//XFileの読み込みデータを保管するクラス
class CXFileManager {
private:
  typedef std::map<string,IXFile *> IXFILE_MAP;
private:
  IXFILE_MAP  m_mapData;
public:

  //=============================================================
 
//読み込んだXFileインスタンスを取り出す(読み込んでなければ読み込んで保管する)
  //=============================================================

  HRESULT GetObject(IXFILE **pXFile,XFILE_LOADDATA *pLoadData,XFILE_LOADTYPE loadType) {
     HRESULT hr = S_OK;
     //戻り値用引数の中身が無い場合、プログラムをとめる
     assert(pXFile != NULL);

    
//既に読み込んだXFileのインスタンスがあるか検索
     IXFILE_MAP::iterator it = this->m_mapData.find(pLoadData->szFileName);
     if(it != this->m_mapData.end()) {
         //あったら戻り値用引数に入れて返す
         *pXFile = it->second;
         return S_OK;
     }

     //戻り値用引数の中身が無い場合、プログラムをとめる
     assert(pLoadData != NULL);
    
//ロードするXFileのタイプが違うなら、とめる
     assert(loadType >= XFILE_TYPE_NUM);
    
//無かったら読み込む
     *pXFile = (loadType == XFILE_STATIC) ? new CXFile() : new CSkinXFile();
     hr = pXFile->LoadXFile(pLoadData);
     if(FAILED(hr))
         return hr;
      this->m_mapData.insert(pair<string,IXFile *>(pLoadData->szFileName,*pXFile));
      return S_OK;
  }


  //=============================================================
  //保管した全てのリソースを開放する

  //=============================================================
  void AllRelease() {
      IXFILE_MAP::iterator it = this->m_mapData.begin();
      for(;it != this->m_mapData.end();it++) {
          it->second->Release();
          delete it->second;
      }
  }
}


ふう、こんな感じですかね

ちなみに、コンパイルは僕の脳内のみで組んだのでコピペで動くかは不明です

コピペで動いた人は褒美として僕に10円ください

大まかに組んだので、読み込みと全て開放しかつけていません。

GetObject()メソッドで戻り値用引数IXFile **を使っているのは、マネージャーのほうにインスタンスの本体を持たせておきたいからです。

マネージャーを使うユーザーはIXFile *のアドレスを渡してやるわけです

なんだかDirectX見たいでかっこよくないですか?

あとはマップコンテナのIXFile *を参照カウンタつきのスマートポインタにしておけば完璧ですねw

こうすれば、マネージャーがXFileリソースの読み込み開放を全て管理することが出来るので、

開放忘れの心配がなくなりますね

そして、肝心のリソースの読み込み、開放ではIXFileインターフェイスが大活躍していますね

IXFileインターフェイスのLoadXFile()メソッドは純粋仮想関数なので、newされたクラスのオーバーライド先のメソッドを実行するわけです

そうすると、クラスごとに違う読み込み処理が行えますね

開放では、クラスを意識せずに一気に開放することが出来ますね

もし、判別したいのであればtypeid演算子やインターフェイスにGetID()メソッドなどを付けて、それから判別する方法もありますね~

そして、IXFileインターフェイスを実装しているクラスはCXFileManagerを使うことができるので、

いちいちクラスごとにリソースマネージャーを作ってやる必要がなくなります

これが、先に言っていたコードを使いまわすことができるという理由なのです

更に、マネージャーをテンプレートで実装してやれば、

型の制限を越えたすごい汎用性を持ったマネージャーが出来上がりますね

インターフェイスは他にもクラスの設計を隠すことが出来ます

製作チームメンバーからある機能のあるクラスをもらったとき、privateやpublicなメンバやメソッドが沢山あって混乱したりしませんか?

去年僕はそれがわずらわしかったので、インターフェイスとインスタンスを作成、開放する関数のみを渡して、中身はDLLにして隠しました

インターフェイスには読み込み、開放、描画、当たり判定ぐらいの純粋仮想関数が書いてあるだけです。

あとは簡単なリファレンスを用意して、ばっちり


とまぁ、いろいろ使い道が広いですね

ちょっと設計がめんどくさいかもですが、是非とも慣れておいて欲しいです

もっと詳しくやってみたいと思う人はGoFのデザインパターンを勉強しておくといいですよ。

オブジェクト指向でよくあるパターンを集めたものです。

オブジェクト指向の基本みたいなものでもあると思うので、オススメです。

「Java言語で学ぶ デザインパターン入門」

と言う本がおすすめです。

Java言語で書かれていますが、とても優しく解説しているので、すごくわかりやすいと思います

さて、結構長々と書いてしまいましたねw

最後まで読んでくれて、ありがとうございました。

それでは、今回はこの辺りで。

あでゅーノシ
PR

COMMENT

NAME
TITLE
MAIL(非公開)
URL
EMOJI
Vodafone絵文字 i-mode絵文字 Ezweb絵文字
COMMENT
PASS(コメント編集に必須です)
SECRET
管理人のみ閲覧できます

無題

  • by 新世界の神
  • 2007/12/19(Wed)22:31
  • Edit
interfaceはC#にもありますね。
これを機会に皆さんには有効活用してもらいたいですね。

コンテナもlistやDICTIONARY( mapのようなもの )コンテナのような便利なものがありますし、他の言語でも有効活用出来そうですね。

ブログ内検索

最新コメント

[01/29 人面犬]
[10/01 8ch]
[09/12 uncle]
[09/10 某卒業生]
[06/07 uncle]

カレンダー

03 2024/04 05
S M T W T F S
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30

テスト

Copyright ©  -- GESブログ --  All Rights Reserved
Design by CriCri / Photo by Geralt / powered by NINJA TOOLS / 忍者ブログ / [PR]