2009-08-26 6 views
0

私は階層内に異なるタイプのハンドルを持っています。多形ハンドル

class Handle { common data } 
class HandleA : Handle { data specific to a } 
class HandleB : Handle { data specific to b } 

ほとんどの部分はハンドルのみを扱います。しかし、HandleA/HandleBの「管理者」の一部では、子クラスのデータにアクセスする必要があります。 例:

void ManagerA::DoSomething(Handle handle) 
{ 
    // needs access to data in handleA 
} 

は、鋳造関係のないこのへの解決策はありますか?

私のアイデア、これまで:
- ManagerA/Bにマップ内の追加データを保存したデータ(追加のハッシュテーブルのルックアップ)
がいることをルックアップするためにハンドルを使用 - ハンドル(handle.DoSomething(中の多型のメソッドを持っています))適切なマネージャメソッドを呼び出す(すべてのハンドルに追加のポインタが必要)
- それをねじ込み、キャストを使用

アイデア?何か不足していますか?それは一つだけに固有のデータなら

おかげ

+0

なぜ、サブクラスHandleXオブジェクトを取得するためにdynamic_castを呼び出さないようにしたいですか? – chollida

+0

おそらく鋳造は多くのC++教科書に「悪いカルマ」を持っていると思われます:ホイッスル: –

+0

それが不透明でないなら、本当にハンドルですか?ハンドルが何であるか分かっていて、それを適切なタイプとして使用する必要がある場合は、なぜキャストを使用しないのですか?キャストに何が問題なの? – Pod

答えて

7

:あなたのhandle引数がするので

void ManagerA::DoSomething(Handle handle) 

は、Handleインスタンスが保持しているものを超えて渡される引数には何も「離れてスライス」WILL NO "余分なデータ"があります。あなたは絶対にポインタまたは参照(おそらくconst、データを変更する必要がない場合は)を渡す必要があります。つまり、通常の多態的アプローチでは、基本クラス内に仮想メソッドを定義し、それらをサブクラスで適切にオーバーライドする必要があります。なぜ完全に正常なアーキテクチャに従うのではなく、に対して OOのアプローチ?正当な理由があるかもしれません(例えば、visitorパターンの一部を採用することを正当化することを正当化する)が、その行に沿って助けることができる十分な力を説明していないだけです。提示された情報には、「仮想メソッドを使用するための再構築者」を提案する必要があります。

4

は - と一種類のみ、dynamic_cast<T>を使用し、それはそれはそこだものです。それ以外の場合は、基本クラスに仮想関数を宣言します。

EDIT:実行時に測定可能なパフォーマンスの差が生じる解決法はありません。 DoSomethingのための署名を変更することについてどう

0

void ManagerA::DoSomething(HandleA handle) 
1

私はハンドルのための多型を使用していないだろう - というポインタよりもされてハンドルを、彼らは絶対に参照されるオブジェクトの実装を隠蔽することになっています。仮想関数を使用すると、ハンドルのユーザーはこれらの関数を呼び出すことができますが、これは間違いです。

2つの一般的な解決策は、キャスティングとマップの使用です。後であれば、ハンドルはクラスでなくてもよく、それはちょうど整数程度であってもかまいません。 Windowsでは、ハンドルはvoid *ポインタです。本当にポインタの後ろに何があるのか​​分かりませんが、本当に気にしません。そして、それは私が心配している限り、ハンドルのポイントです。

0

あなたの最初と3番目のアイデアはうまくいくはずです。別の考え方は、double-dispatchを使用することです(Wikipediaの記事が分かりやすいかどうかは分かりませんが、マイヤーのMore Effective C++の記事/説明は20奇数ページです)。Handle::DoSomething(Manager&)のような仮想メソッドを実装することを意味します。あなたがやっているように、値によって引数を受け

0

もう1つの可能性は、具体的な型を各ハンドルに格納し、場合によっては整数または列挙型として格納することです。可能なすべての具体的なハンドルタイプをハードコードするか、ある種のタイプの登録メカニズムを使用します。明らかにこのアプローチには独自の欠点がありますが、です。別の可能性があります。これは、イベントタイプに使用されるX-Windowsのアプローチです。イベントデータ構造は、すべての可能なイベントデータの集合体であり、特定のイベントの真のデータ型を示す型変数を持つ。それが良いと言っているわけではなく、単にそれがオプションであると言っているだけで、ダイナミックキャスティングを必要としないものです。

enum HandleType 
{ 
    HANDLE_TYPE_A, 
    HANDLE_TYPE_B 
}; 

class Handle 
{ 
private: 
    HandleType _type; 
protected: 
    Handle(HandleType type) : 
    _type(type) 
    {} 
public: 
    HandleType get_type() const 
    { return _type; } 
}; 

class HandleA 
{ 
    HandleA() : 
    Handle(HANDLE_TYPE_A) 
    {} 
}; 

void ManagerA::DoSomething(Handle& handle) 
{ 
    if (handle.get_type() == HANDLE_TYPE_A) 
    do_something(); 
}