2009-10-08 17 views
5

C++でのC#typeof-commandの動作をシミュレートする方法は?C言語でtypeofを使用する方法

C#の例:

public static PluginNodeList GetPlugins (Type type) 
{ 
... 
} 

はコール:この使用してC++を実装する方法を

PluginManager.GetPlugins (typeof(IPlugin)) 

?たぶん、QTまたはBoostライブラリが解決策を提供しますか?

.GetPlugins(...)をファイル(.soまたは.dll)からロードする方法で実装する場合はどうですか?

+0

何私の質問の後半部分について。私には、私が何度も直面する最も難しい問題と問題の1つです。誰かが私を正しい方向に向けることができれば、非常に高く評価されます。 –

答えて

2

完全な型のような動作が必要な場合は、RTTI (run-time type information)を使用する必要があります。多くのコンパイラでは、実行時のオーバーヘッドが発生するため、RTTIの使用を明示的にアクティブ化する必要があります。

次に、typeidまたはdynamic_castを使用してオブジェクトのタイプを見つけることができます。

typeidを使用しない場合は、継承、ポインタ、および/またはオーバーロードを使用する必要があります。ブーストかもしれないあなたを助けるが、あまりにも難しくありません。

例1:

class Iplugin { ... } 

class Plugin1 : public Iplugin { ... } 
class Plugin2 : public Iplugin { ... } 

void getplugins(Iplugin* p) { 
    // ... you don't know the type, but you know 
    // what operations it supports via Iplugin 
} 

void getplugins(Plugin1& p) { 
    // expliticly handle Plugin1 objects 
} 

あなたはRTTIと型IDの使用を回避するいくつかの方法があります見ることができるように。

+1

キャストがvtableを持つクラスを超えていることが重要です。RTTIはdynamic_castを実行するために依存します。 – fbrereto

+1

私はRTTIがランタイムオーバーヘッドを招くとは思わない。むしろクラスごとの追加情報をvtableに格納する必要があるため、生成されるコードはわずかに大きくなります。 前述のとおり、クラスにはvtableが必要です。そのようなクラスには、ほとんどの場合、仮想デストラクター(vtableを持つことを保証する)が必要です。 – TrayMan

+1

間接的には、コードサイズが大きいためランタイムオーバーヘッドが発生する可能性があります。 – rlbond

8

下図のようにあなたはタイプをテストするためにはdynamic_castを使用することができます。

IPlugin* iPluginPtr = NULL; 
iPluginPtr = dynamic_cast<IPlugin*>(somePluginPtr); 

if (iPluginPtr) { 
    // Cast succeeded 
} else { 
    // Cast failed 
} 
+2

これが機能するには、RTTIを有効にする必要があることに注意してください。 – csl

+13

はい、言い換えれば、言語はC++でなければなりません。標準C++にはRTTIが含まれています。コンパイラがあなたにそれをオフにすることを許可するという事実は、関連してはいけません。これは非標準的な動作です。言語の一部を無効にし始めると、もちろんそれに依存するコードは動作しません。 FortranやCではなく、C++コンパイラにコードを供給しなければならないことも指摘しておきます。 – jalf

+1

@jalf:確かに、あなたは確信しています。コンパイラとは関係ありません。しかし、彼らはそうしているので、あなたが実際にやらなければならないかもしれないことに注意するのは害ではありません。私はコンパイラがこれを行うので、 "あなたが使っていないものを支払わない"と思います。 – csl

5

この動作はRTTI (Run time type information)と呼ばれています。この手法は避けるのが最善ですが、状況によっては有益な場合もあります。

これを解決する大きな方法が2つあります。第1の方法は、クラス固有の整数参照コードを返す純粋仮想関数を持つインタフェースを記述することです。このコードを使用して、特定のタイプを表すことができます。これらの整数は、特定の列挙型に格納することができます。

派生クラスでは、メソッドをオーバーライドしてそのクラス固有の型を返すことができます。 実行時に、例えば、Plugin-> getType()を呼び出すと、その特定の型が返されます。その後、ポインタにstatic_castを実行して、派生型の正しいポインタを取得することができます。

第2の方法は、typeidを使用してオブジェクトのクラスタイプを取得することです。これはコンパイラに依存します。 dynamic_castを使用してポインタをキャストすることもできます。 dynamic_castは、間違った型にキャストされているときにnullポインタを返します。正しいタイプでキャストされると有効なものです。動的キャストメソッドは、上記のgetTypeメソッドよりもオーバーヘッドが大きい。

+0

RTTIは、タイプセーフな動的ダウンキャスティングを行うために必要です。 "typeof"(GCC拡張)または "auto"/"decltype"(C++ 0x)機能は提供しません。 – Adisak

2

この問題を回避する設計が最適です。オブジェクト指向をうまく利用すれば、通常、各オブジェクトの識別子を格納する基本クラスを使用して、オブジェクトの型を問い合せる独自のシステムを作成できます。

dynamic_castは、オブジェクトの型を見つけるのに文字列比較を使用することが多く、それは本当に遅くなるので、常に使用しないでください。

1

ブーストには型があります。 C++ 0xはtypeofと呼ばれるのではなく、同じ種類の機能を提供する 'auto'と 'decltype'の両方を持っています。

あなたはこのケースであなたが本当に探しているものを提供していないと確信しています。ほとんどの場合、必要なものだけを提供しています。

2

GCCでtypeof()を使用できます。他のコンパイラでは、それはサポートされていないか、クレイジーなテンプレートマングリングをしたり、(ブーストのように)非常にコンパイラ固有の "バグフィーチャ"を使用する必要があります。

0

「C++でtypeof()を取得する方法」に直接は答えませんが、C++でプラグインを実行する方法を見ているという質問から推測します。その場合、(まだ)Boost.Extensionライブラリに興味があり、reflection部分にある可能性があります。

1

確かにオーバーロードを使用しますか?

static PluginManager::GetPlugins(Type1 &x) { 
    // Do something 
} 

static PluginManager::GetPlugins(Type2 &x) { 
    // Do something else 
} 

してから呼び出す:

PluginManager::GetPlugins(IPlugin);