2010-11-26 17 views
6

共通の基底クラスから派生したすべてのクラスに一意の "クラスID"が割り当てられているC++のメカニズムを実装しようとしています。たとえば:共通基底​​クラスの派生クラスの型ID

class BaseClass 
{ 
    //... 
    public: unsigned int GetID(void); 
    //... 
}; 
class DerivedClass : public BaseClass 
{ 
} 

クラスDerivedClass、およびBaseClassの他のすべての子供たちは、DerivedClassに追加されたコードを追加せずに一意の識別子を返すことができるはず... C++は、しかし、私にとってこれはかなり困難にしています。任意のアイデアをいただければ幸いです。

ありがとうございます! --- Dan

+0

のIDは、intであるか、任意の一意の型である必要があります。 typeidによって返されたものあなたのBaseClassは多態性ですか? – Chubsdad

+0

私の基本クラスは多相ですが、RTTI(性能とメモリの両方)に伴うオーバーヘッドの正確な性質について、堅実で完全な説明を見つける能力がないため、私はそれを完全に避けようとしています。 – Dan

答えて

2

あなたはtypeiddynamic_castに精通しているとは言えません。

あなたの問題を解決する可能性があります。

そうでない場合は、その理由を説明してください。

乾杯& HTH。、

+0

これはコメントではありませんか? – Chubsdad

+0

申し訳ありませんが、忘れてしまいました。可能な場合はRTTIを避けようとしています。アプリケーションにパフォーマンスが重大であるため、 – Dan

+0

@Chubstad:いいえ、コメントではありません。 'typeid'はタイプIDが必要なときの一般的な答えです。あなたはその名前からそれを推測することさえできます。 –

1

アルフが言うように、これは必要ありません。 typeidはすでに識別子が整数ではありませんが、一意のクラス識別子を与えています。私は、「共通の基底クラス」の条件を緩和することが許可されていた場合だけで笑いのために、:

inline unsigned int counter() { 
    static unsigned int count = 0; 
    return ++count; 
} 

struct BaseClass { 
    virtual unsigned int GetID() = 0; 
    virtual ~BaseClass() {} 
}; 

template <typename D> 
struct IntermediateClass : BaseClass { 
    virtual unsigned int GetID() { 
     static unsigned int thisid = counter(); 
     return thisid; 
    } 
}; 

// usage 
struct Derived : IntermediateClass<Derived> { 
    ... 
}; 

あなたはそれがマルチスレッドプログラムで使用するかどうcounterにスレッドセーフを追加する必要があると思います。

明らかに、IDは、プログラムの特定の実行内で一意でしかありません。

継承階層が深く、異なるクラスの署名が異なるコンストラクタがたくさんある場合は、派生クラスと直接ベースクラスの間にIntermediateClassを挿入する必要があるため、少し毛深いです。次のようにしかし、あなたは常にすべてのことの救済することができます

inline unsigned int counter() { 
    static unsigned int count = 0; 
    return ++count; 
} 

struct BaseClass { 
    virtual unsigned int GetID() = 0; 
    virtual ~BaseClass() {} 
}; 

template <typename D> 
unsigned int ThisID(const D *) { 
    static unsigned int thisid = counter(); 
    return thisid; 
} 

// usage 
struct Derived : BaseClass { 
    // this single line pasted in each derived class 
    virtual unsigned int GetID() { return ThisID(this); } 
    ... 
}; 

私はここに新しい言語機能のための「機会」が存在だと思う:1とテンプレート関数として基底クラスで定義されている仮想関数を " typename "テンプレートパラメータであり、派生クラスをテンプレート引数として使用して、派生クラスごとに自動的にオーバーライドされます。架空の構文、仮想テンプレート関数が不正なので:

struct BaseClass { 
    template <typename Derived> 
    virtual unsigned int GetID() { 
     static unsigned int thisid = counter(); 
     return thisid; 
    } 
    virtual ~BaseClass() {} 
}; 

再実装自分自身をRTTIしたい、心に基づいて言語機能を正当化するのは難しい...

+0

これはうまくいきますが、2つの派生クラスが2つの異なるクラスから継承しているので、私はクラスの多型を失います。 – Dan

+0

@ダン:あなたのクラスが多形であると言って以来、私はそれをちょっとジッとしてきました。最初のオプションでは、すべてがBaseClassから間接的に導出されるため、引き続きDerivedオブジェクトをBaseClass *から使用できます。 2番目のオプションでは、すべてがBaseClassから直接派生しているため、コンストラクタの管理がはるかに簡単ですが、各派生クラスに1つの(同一の)関数を追加する必要があります。 –

+0

ラットは、各派生クラスの行が同一ではないことを認識しました。これらの派生クラスのうちの1つが別のクラスを拡張し、2つのGetIDImpl関数を継承する場合にコールを曖昧さをなくすために、私はそのオプションを変更します。 –

0

これは、派生クラスの変更が必要ですしかし、RTTIの信頼性の欠如がtypeid、dynamic_castのよく確立されたルートを避ける唯一の理由なら、THEN

これは良い賭けになるはずです。また、RTTIによって 'type_info'と比較して 'int'を返します。

class BaseClass{ 
    //... 
    public: 
     virtual unsigned int GetID(void); 
    //... 
}; 

class DerivedClass : public BaseClass{ 
public: 
    virtual unsigned int GetID(void); 
}; 
+0

私は各DerivedClassのために別々の実装を避けようとしています。それは私の問題です。私はそれを明確にしていない場合は申し訳ありません。 – Dan

2

あなたはアルフに耳を傾ける必要があります:)ここに私の分析です:実装の識別が仮想関数多型を脅かす純粋な世界では、必要とすることはできませんし、必要に応じてはいけません。実際のプログラミングの汚れた世界では

自分の考えが純粋であれば、あなたはなど、

を、ディスクにデータをマーシャリング診断メッセージを識別し、制御フローを追跡、使用状況の統計を蓄積として一意に識別するためのいくつかの理由があるかもしれあなたのデザインは間違っています。離れて、ユニークなIDを必要としない理由を理解してください。

あなたが思考が現実に崩れているなら、あなたはすでにあなたの要件を満たすためにパフォーマンスとメモリの価格を支払うつもりであり、仕様によっては組み込みの言語機能を使用するコストは支払う価値があります。非侵襲的な識別サービスを提供するという目標を達成する唯一の方法です。非侵襲的なことは、派生クラスごとに何も追加する必要がないということです。明らかに、何かを追加しなければならないので、そうしたくなければ、コンパイラがあなたのために追加するものを受け入れるしかありません。

ここでの主な問題は、動的にロードされる共有ライブラリ(DLLS)を使用している場合、RTTIが期待どおりに動作しない可能性があることです。これは単にタイプIDに悪影響を及ぼすだけでなく、捕まえられると予想される例外を捕まえるのを防ぐことができます(私は噛まれました!)。 vtableやその他のRTTIが一意に作成されるように注意する必要があるかもしれません。例えば、デストラクタ上のvtablesがインラインでない場合、vtablesが複数の場所で生成され、一意性を破壊する可能性があるためです。ダイナミックローディングのためのISO標準化のサポートがない場合、ここでいくつかのハッキングが必要かもしれません。

+0

あなたはRTTIの内部動作についてかなり知っているようです。この機能を実装するためにコンパイラレベルで使用されるメカニズムの詳細な説明があるオンラインの場所はどこですか? – Dan

+0

私はリンクを手に入れることはできませんが、見える場所はもちろん、gcc開発サイトと、当初はAMDによって制作され、現在は業界団体によって管理されている業界のABI仕様です。これは、基本的に、引数をレジスタに渡す、例外処理、動的リンケージなど、さまざまなC++機能のx86_64プロセッサに使用されるAPIを配置します。 – Yttrill

関連する問題