2011-01-16 14 views
2

C++で渡された型名(文字列)を使用してオブジェクトの標本を返すことは可能ですか? 私は基本抽象クラスBaseといくつかの派生クラスを持っています。コード例:名前でオブジェクトを作成します

class Base 
{ 
    /* ... */ 
}; 

class Der1 : public Base 
{ 
    /* ... */ 
}; 

class Der2 : public Base 
{ 
    /* ... */ 
}; 

そして、私はのような機能を必要とする:誘導体クラスの

Base *objectByType(const std::string &name); 

数は変更可能であると私はnameの切り替えや手で新しいオブジェクト型を返すようなものを作りたくありません。とにかくそれを自動的に行うことはC++で可能ですか?

p.s.私は純粋なC++コード(クロスプラットフォーム)が必要

dynamic_cast<Der1>(objectByType("Der1")); 

:ように使い方はすべきに見えます。ブーストの使用は許可されています。

+0

OS固有の質問です。どのOSについて話していますか? –

+0

@sad_man、更新をご覧ください。私はクロスプラットフォームのバージョンが必要です。 – Ockonal

+0

「デリバティブの数」はどのように変更可能ですか?あなたのアプリケーションの後にコンパイルされた外部ライブラリからデリバティブを呼び出そうとしますか? –

答えて

2

factory methodという文字列をif...else if...のシーケンスなしで書くことができる素晴らしいテクニックがあります。

は(私の知る限り、このコードはコンパイル時に生成されるよう、あなたがC++でやりたいことが実際に可能ではない、ということに注意してください。「ファクトリメソッド」Design Patternは、この目的のために存在する)

まず、あなたを派生クラスにはglobal repositoryを定義します。 std::map<std::string, Base*>の形式であってもよく、すなわち、派生クラスの名前をそのクラスのan instanceにマップする。

派生クラスごとにdefault constructorを定義し、そのクラスのオブジェクトをクラス名でリポジトリに追加します。また、クラスの静的インスタンスを定義します:静的変数の

// file: der1.h 
#include "repository.h" 

class Der1: public Base { 
public: 
    Der1() { repository[std::string("Der1")] = this; } 
}; 

// file: der1.cpp 
static Der1 der1Initializer; 

コンストラクタさえmain()前に実行されるので、あなたのmain開始は、あなたはすでに、すべての派生クラスのインスタンスを使用して初期化リポジトリを持っていたときにしています。

ファクトリメソッド(例:Base::getObject(const std::string&))は、クラス名のリポジトリマップを検索する必要があります。次に、見つかったオブジェクトのメソッドを使用して、同じタイプの新しいオブジェクトを取得します。もちろん、サブクラスごとにcloneを実装する必要があります。

このアプローチの利点は、新しい派生クラスを追加するときに、追加が新しいクラスを実装するファイルにのみ制限されることです。リポジトリと工場コードは変更されません。もちろん、プログラムを再コンパイルする必要があります。

+2

デフォルトのコンストラクタはこれを行うための悪い方法です。ファクトリのsetup関数の呼び出しで初期化される 'int'のような通常のグローバル変数を作成するだけです。例えば'static int g_factoryDe​​r1Registration = Der1Factory :: Register();'または、ネストされたヘルパークラスのインスタンスを作成します。しかし、ファクトリを登録するために、ファクトリが生成しているタイプのインスタンスを作成しないでください。ファクトリは、すべての可能な方法で単一の責任原則に違反します。 –

+0

@Ben Voigt:これを指摘してくれてありがとう。実際には、専用の 'Der1Factory :: Register()'メソッドを使うほうが良く見えます。 – davka

+0

良い考えですが、switch/if文がありません。 – Ockonal

0

はい、可能です! Activator Typestringですべてを作成することができ、パラメータのリストを与えることもできるので、メソッドは最適な引数セットで適切なコンストラクタを呼び出します。

+1

私は質問が.Netのために求められているとは思わない。 –

+0

クロスプラットフォームで、C++に対応していますか?私はそれが.Netやsmthのようなものに基づいているのを見ます。 – Ockonal

+3

間違った言語、間違ったフレームワーク(OPがC++の代わりにC++/CLIを使用していると言及されていない場合を除きます)。 –

0

私が誤解しない限り、typeidのキーワードは、探しているものの一部である必要があります。

+0

'typeid'は、型から型記述オブジェクト(型名を文字列として含む)へのマッピングを提供しますが、逆マッピングはC++では利用できません。 – Philipp

2

C++でこれを行うことはできません。

1つの選択肢は、工場に書き込んで渡された名前を入れ替えることですが、あなたはそれをしたくありません。 C++では、dynamic_cast以外の実際のランタイムリフレクションのサポートは提供されていないため、この種の問題は解決するのが難しいです。

+1

あなたは 'switch'なしで工場を書くことができます - 以下の私の答えを見てください。 – davka

0

これはできません。あなたはobjectByType機能を自分で記述する必要があります:

Base* objectByType(const std::string& name) { 
    if (name == "Der1") 
    return new Der1; 
    else if (name == "Der2") 
    return new Der2; 
    // other possible tests 
    throw std::invalid_argument("Unknown type name " + name); 
} 
0

C++はreflectionをサポートしていません。

私の意見では、これはJavaがC++に勝つ単一のポイントです。
(これはあまりにも多くの投票を得ることはできません)

QtのMOCと同様に、カスタムプリプロセッサを使用すると、そういったことが実現できます。