__interfaceに定義するメソッドについて教えてください!
描画エンジン(engine.dll)を作成しているのですが、アプリ(App.exe)からは呼んで欲しくないメソッドをインターフェイスに定義する必要があり困っています。具体的には、以下のDrawメソッドになります。
// 形状インターフェイス[engine.dll]
__interface IShape {
bool Draw(); // ★CRenderクラスから呼ばれる
bool SetPos( int x, int y );
};
// 描画クラス[engine.dll]
class CRender {
bool DrawShape( IShape* pShape ); // pShape->Draw();をする
};
// アプリ[App.exe]
CRender* pRender = new CRender();
IShape* pShape = new CPolygon();
pShape->SetPos(100, 100);
pRender->DrawShape( pShape );
DrawメソッドはCRenderが呼ぶメソッドなので、アプリには公開しなくてもよいメソッドになっています。公開する必要がないので、隠蔽するのが正しいと思っていますが、良い案がございましたらご助言ください。
No.2ベストアンサー
- 回答日時:
COMの考え方を参考にするといいと思います。
サンプルを書いてみましたので読んでみてください。
■ アプリ用ヘッダ
#define __interface struct
__interface IShape {
virtual bool SetPos( int x, int y ) = 0;
};
__interface IRender {
virtual bool DrawShape( IShape* pShape ) = 0;
};
enum {
TYPE_SHAPE,
TYPE_POLYGON,
};
void CreateObject(int typeID, void** ppObj);
■アプリ実装
main()
{
IShape* pShape = 0;
IRender* pPolygon = 0;
CreateObject( TYPE_SHPAE, &pShape);
CreateObject( TYPE_POLYGON, &pPolygon);
pShape->SetPos(100, 100);
pRender->DrawShape( pShape );
delete pRender;
delete pShape;
}
■engine.dll
インターフェースの実装
// engine.dll の実装個所
class CShape : public IShape {
public: // interface 実装
bool SetPos( int x, int y );
public:// CShape 公開メソッド
bool Draw( HDC hDC );
};
class CPolygon : public IRender {
public: // interface 実装
bool DrawShape( IShape* pShape )
{
((CShape*)pShape)->Draw( m_hDC );
}
public:// CPolygon 公開メソッド
protected:
HDC m_hDC;
};
■オブジェクト生成関数
void CreateObject(int typeID, void** ppObj)
{
switch( type ID) {
case TYPE_SHAPE:
*ppObj = new CShape;
break;
case TYPE_POLYGON:
*ppObj = new CPolygon;
break;
}
}
ご回答頂きありがとうございます!
>((CShape*)pShape)->Draw( m_hDC );
なるほど!エンジンが生成を担うことで(CreateObjectメソッド)、エンジン内部では生成した型へのキャスト(dynamic_cast)が可能ということですね!
これなら呼ばれないメソッドも隠蔽でき、HDC型も知られずに済みそうです。大変貴重なご助言感謝致します。
No.1
- 回答日時:
言語がC++か、C#かC++マネージかなにかわかりませんが、
C++ということで話を進めます。
C++であれば、一番楽なのは、インターフェイスを使用せず、
抽象化クラスを使用して、Drawメソッドをprivateメソッドに指定し
Renderクラスを IShapeインターフェイスのフレンドにすれば良いでしょう。
インテリセンスなどからはメソッドが消えないかも知れませんが、
アクセスは制限されるので呼び出そうとすればコンパイルエラーになります。
本来、__interfanceの識別子は動作がコンパイラに依存するものなので
あまり、使わない方が良いような気がします。
リファクタリングすれば、
もっとスマートになると思いますが、
質問者さんのコードを変えて
C++で書くならこんな感じでしょうか。
//抽象クラス(Interface)
class IShape{
public:
friend class CRender;
virtual void SetPos(int x, int y) = 0;
private:
virtual void Draw() = 0;
};
class CPolygon : public IShape {
public:
CPolygon(){}
~CPolygon(){}
void SetPos(int x, int y){ m_x = x; m_y = y;};
private:
void Draw(){ printf( "x:%d y:%d", m_x, m_y ); };
int m_x, m_y;
};
class CRender {
public:
CRender(){}
~CRender(){}
bool Draw(IShape*Drawer){
Drawer->Draw();
return true;
}
};
int main( void )
{
// IShape S;//抽象クラスはインスタンス化できないのでエラー
IShape *S; //インスタンス化されないのでOK
CRender R;
S = new CPolygon;//IShapeを実装であるPolygonクラスでインスタンス化する
S->SetPos( 100, 200 );//publicなので呼び出しが可能
// S->Draw();//privateのためクラス外からはアクセスできないのでエラー
R.Draw(S);//RenderクラスはIShapeとpublicフレンドなので内部で呼び出しが可能
delete S;
return 0;
}
※全角スペースは半角かタブに変換してください
早速のご回答ありがとうございます!※ご察し頂いた通り言語はC++になります。
>本来、__interfanceの識別子は動作がコンパイラに依存するものなので
クロスプラットフォームも視野に入れていますのでご指摘感謝致します!
>Renderクラスを IShapeインターフェイスのフレンドにすれば良いでしょう。
なるほど。勉強になります!
また、記載不足で大変申し訳ございませんが、実際にはDrawの引数となるHDCをヘッダーに書きたくないという意図もあります。
// Shapeインターフェイス[公開ヘッダー]
class IShape {
public:
~IShape(){}
virtual bool SetPos(int x, int y) = 0;
virtual bool Draw(HDC hDC) = 0; // ★HDCを引数にとります。
};
// 描画インターフェイス[公開ヘッダー]
class IRender {
public:
~IRender(){}
virtual bool DrawShape( IShape* pShape ) = 0;
};
// 描画クラス[非公開ヘッダー]
#include <windows.h>
class CWinRender : public IRender {
HDC m_hDC;
public:
virtual bool DrawShape( IShape* pShape ){
pShape->Draw( m_hDC ); // HDCメンバーを渡す
}
};
// アプリ
#include <IShape.h>
#include <IRender.h>
Update(IRender* pRender, IShape* pShape ){
pRender->DrawShape( pShape );
}
CWinRender以外のコードはHDC(windows.h)をインクルードしていないので、Linuxなどでもビルドできるという意図があります。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・14歳の自分に衝撃の事実を告げてください
- ・架空の映画のネタバレレビュー
- ・「お昼の放送」の思い出
- ・昨日見た夢を教えて下さい
- ・【お題】絵本のタイトル
- ・【大喜利】世界最古のコンビニについて知ってる事を教えてください【投稿~10/10(木)】
- ・メモのコツを教えてください!
- ・CDの保有枚数を教えてください
- ・ホテルを選ぶとき、これだけは譲れない条件TOP3は?
- ・家・車以外で、人生で一番奮発した買い物
- ・人生最悪の忘れ物
- ・【コナン30周年】嘘でしょ!?と思った○○周年を教えて【ハルヒ20周年】
- ・ハマっている「お菓子」を教えて!
- ・最近、いつ泣きましたか?
- ・夏が終わったと感じる瞬間って、どんな時?
- ・10秒目をつむったら…
- ・人生のプチ美学を教えてください!!
- ・あなたの習慣について教えてください!!
- ・牛、豚、鶏、どれか一つ食べられなくなるとしたら?
- ・都道府県穴埋めゲーム
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
String.containsの反対機能はあ...
-
Java初級 引数に適用できません
-
contextってなんですか?
-
Google Apps Script で getRang...
-
Java初心者です。例外のキャッ...
-
return new使用時
-
レコード件数の表示
-
なぜprotected overrideなのか
-
StringBufferからStringへキャ...
-
Strutsでチェックボックスの値...
-
YYYYMMDD書式の日付に対する適...
-
テキストファイルに書かれた文...
-
メソッドの引数に指定されてい...
-
シェルスクリプトからのJavaメ...
-
C# 点の描き方をおしえてくだ...
-
親フレームから子フレームへ値...
-
C# 他のnamespaceにあるメソッ...
-
Javaの文法
-
staticと+=の意味を・・・
-
staticのメリット、デメリット
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
Java初級 引数に適用できません
-
String.containsの反対機能はあ...
-
レコード件数の表示
-
YYYYMMDD書式の日付に対する適...
-
StringBufferからStringへキャ...
-
Strutsでチェックボックスの値...
-
Java初心者です、エラーの意味...
-
Google Apps Script で getRang...
-
C# でメソッドに送られてきたOb...
-
メソッドの引数に指定されてい...
-
Fileの読み取り専用の解除
-
なぜprotected overrideなのか
-
return new使用時
-
クラスを作るとメソッドの数が...
-
javaに"search"という関数 or ...
-
C# 点の描き方をおしえてくだ...
-
親の親のメソッドを呼ぶには?
-
Javaの関数名が長い?
-
CSVから読み込んだデータの保持...
-
別クラスのmainメソッドの実行
おすすめ情報