2012-01-24 15 views
2

クラス(クラスを扱う)について扱う適切なインターフェイスは何かをアドバイスしていますが、実際のクラス(メタ・アスペクト)の一部ではありません。これはいくつかの説明を必要とします...クラスのメタ面を扱うための適切なインターフェースは何ですか?

私の具体的な例では、C++で提供されているものよりも少し複雑なカスタムRTTIシステムを実装する必要があります(私が必要とする理由はありません)。私のベースオブジェクトはFooBaseであり、このベースの各子クラスはFooTypeInfoオブジェクトに関連付けられています。

// Given a base pointer that holds a derived type, 
// I need to be able to find the actual type of the 
// derived object I'm holding. 
FooBase* base = new FooDerived; 

// The obvious approach is to use virtual functions... 
const FooTypeInfo& info = base->typeinfo(); 

仮想関数を使用してオブジェクトの実行時の型を処理することは、私にとって正しいと感じません。私はオブジェクトの実行時の型をクラスの範囲を超えたものと考える傾向があり、明示的なインタフェースの一部であってはならない。次のインターフェイスは、インターフェイスは、クラスの一部ではないにもかかわらず、実装はまだこれが動作するためには、仮想関数を使用する必要があります、しかし

FooBase* base = new FooDerived; 
const FooTypeInfo& info = foo::typeinfo(base); 

...私はたくさんより快適に感じさせます

class FooBase 
{ 
    protected: 
    virtual const FooTypeInfo& typeinfo() const = 0; 
    friend const FooTypeInfo& ::foo::typeinfo(const FooBase*); 
}; 

namespace foo 
{ 
    const FooTypeInfo& typeinfo(const FooBase* ptr) { 
     return ptr->typeinfo(); 
    } 
} 

あなたは私が(私にとってより適切な感じ)、この第2のインターフェースを使用して、多少複雑な実装に対処すべきだと思いますか、私は最初のインターフェイスで行くshoud?


@Sethカーネギー

あなたが本当に行うことはできませんので、あなたも...派生クラスがRTTIの一部であることについて知られたくない場合、これは難しい問題ですFooBaseコンストラクタ内のインスタンス化されるクラスの実行時の型に依存するもの(同じ理由で、ctorまたはdtor内で仮想メソッドを呼び出すことはできません)。

FooBaseは、階層の共通基盤です。ボイラープレートの量を減らし、タイプの定義を簡単にする別のクラステンプレートも用意されています。 Pythonの派生オブジェクトで動作する別のPythonFooクラスがあります。システムの作品はここに見つけることができる方法の詳細

template<typename FooClass> 
class CppFoo : public FooBase 
{ 
    private: 
    const FooTypeInfo& typeinfo() const { 
     return ::foo::typeinfo<FooClass>(); 
    } 
}; 

class SpecificFoo : public CppFoo<SpecificFoo> 
{ 
    // The class can now be implemented agnostic of the 
    // RTTI system that works behind the scenes. 
}; 

いくつかの詳細:
https://stackoverflow.com/a/8979111/627005

+0

カスタムRTTIに参加するすべてのクラスは、 'FooBase'から継承しなければならないものとします。それぞれのクラスが型を与えるために仮想関数をオーバーライドさせるのではなく、一意のIDを持つコンストラクタ 'FooBase(int)'を呼び出し、メンバ 'const int'を初期化して関数' foo :: typeinfo'は、仮想関数呼び出しの代わりに変数を取得するだけですか? –

+0

@SethCarnegieカスタムRTTIが必要な理由の1つは、自分のプログラムがPythonをスクリプト言語として組み込んでいるため、RTTIシステムが2つの言語間で一貫している必要があるということです。 IDを2つの言語の間で一意に保つことで生じるいくつかの問題があるかもしれません。 [cont'd] –

+0

@SethCarnegie [cont。]あなたが提案したものがある定型文を紹介するという問題もあります。私は、スクリプト定義の型がこのような実装の詳細を処理する必要はありません。現在のところ、通常のPythonアプリケーションと同じようにクラスを作成するだけです。そのままにしておきたいと思います。 –

答えて

0

あなたはtypeidキーワードと使用することにより、静的タイプと動的タイプを結ぶことができます識別の手段としてstd::type_infoオブジェクトを返しました。さらに、目的のために特別に作成された別のクラスにtypeidを適用すると、その名前はまだ事前に知られている必要がありますが、あなたが属しているクラスに対して全く非侵害的になります。 typeidが動的多型をサポートするタイプに適用されていることが重要です - それはいくつかのvirtual機能を持っている必要があります。ここで

は一例です:std::type_infoが適切なオブジェクトであり、彼らがユニークであると命じたことから、あなたがコレクションでそれらを管理するため、インタフェースからの照会タイプを消去することができ、言うこと

#include <typeinfo> 
#include <cstdio> 

class Base; 
class Derived; 

template <typename T> class sensor { virtual ~sensor(); }; 

extern const std::type_info& base = typeid(sensor<Base>); 
extern const std::type_info& derived = typeid(sensor<Derived>); 

template <const std::type_info* Type> struct type 
{ 
    static const char* name; 

    static void stuff(); 
}; 

template <const std::type_info* Type> const char* type<Type>::name = Type->name(); 

template<> void type<&base>::stuff() 
{ 
    std::puts("I know about Base"); 
} 

template<> void type<&derived>::stuff() 
{ 
    std::puts("I know about Derived"); 
} 

int main() 
{ 
    std::puts(type<&base>::name); 
    type<&base>::stuff(); 

    std::puts(type<&derived>::name); 
    type<&derived>::stuff(); 
} 

は言うまでもなく:

template <typename T> struct sensor {virtual ~sensor() {}}; 

struct type 
{ 
    const std::type_info& info; 

    template <typename T> 
    explicit type(sensor<T> t) : info(typeid(t)) 
    {}; 
}; 

bool operator<(const type& lh, const type& rh) 
{ 
    return lh.info.before(rh.info); 
} 

int main() 
{ 
    std::set<type> t; 
    t.insert(type(sensor<Base>())); 
    t.insert(type(sensor<Derived>())); 

    for (std::set<type>::iterator i = t.begin(); i != t.end(); ++i) 
    std::puts(i->info.name()); 
} 

もちろん、両方のミックスとマッチングが可能です。

2つの制限:

  • ここには実際のイントロスペクションはありません。巧妙なメタプログラミングを介してtemplate struct sensorに追加することができます。
  • サポートしたいすべてのタイプの名前を事前に知っておく必要があります。

可能なバリエーションの1つは、クラス名がすでに分かっている実装ファイルにstatic const sensor<Myclass> rtti_MyClass;などのRTTI「フレームワークフック」を追加して、コンストラクタに作業をさせることです。また、センサーでのイントロスペクションを可能にするために、この時点で完全な型にする必要があります。

関連する問題