2016-05-26 5 views
5

多型オブジェクトの型を実行時に決定する必要があるプロジェクトを処理しようとしているので、型変換できます。 私が何を意味するかの例:C++実行時に多態性オブジェクトの型を決定する

class A{ 
}; 
class B: public A{ 
    public: 
     void foo(){ 
      printf("B::foo()\n"); 
     } 
}; 

その後、私は基本的に、このようなとして格納されているBオブジェクトの束があります:

std::vector<A*> v; 
v.push_back(new B()); 

をそして、私のように定義された特定のオーバーロードされたメソッドを呼び出す必要があります:

void bar(B* b){ 
    b->foo(); 
} 

vに格納されているオブジェクトを渡した後。私が午前の問題は、私の実際のユースケースでは、私はコンパイル時にBの種類を知らないので、私はちょうどbar((B*)v.get(0));

ソリューション私が考えていると言ってbarを呼び出すことができないということです私は、それぞれのオブジェクトが実行時にある型を何らかの形で決定する必要があるかもしれないので、それをキャストしてbarに渡すことができます。

私が今までに試した解決策は、decltypeを使用することでしたが、実行時に渡された値ではなく、渡された値の静的型を返すだけで機能しませんでした。

また、私はできるだけ小さくしたいので、このプロジェクトには第三者図書館を使用したくありません。

ありがとうございました。

編集:私は私は私は私の問題を記述したときに私は何を意味するのかで十分に明確だったとは思わない

。私の実際のユースケース(ここに投稿しようと少し長いですが、必要に応じてその部分を投稿することはできますが)は、基本クラス(ここではAと表示されています)があるライブラリを作成しようとしています。ユーザーによって独自のカスタムクラス(ここではBと表されます)に拡張されます。私の例では、B::foo()は、単にAの各サブクラスが、後で(barというように)いくつかの方法で処理される独自のデータメンバーをどのように持つことができるかを表しています。これはまた、Aが単純にいくつかの仮想fooメソッドを持つことができない理由です。

Bはユーザ定義であると考えられているので、コンパイル時には何か分かりませんが、リンク時(リンクは後で来るので)で行います。だから、私が理解しているから、Bの可能性を知る必要があるので、dynamic_cast(サムとレミーが提案したように)の使用はうまくいきません。それは私にとってうまくいくものに非常に近いものでしたが。すべての可能なサブクラス(プリプロセッサのマクロやテンプレートなど)を得る方法があれば、これはうまくいくと思います。

私はこの時間をより良く説明してくれることを願っています。ご協力いただきありがとうございます。

編集2:別の明確化のポイント:私が取り組んでいる実際のプロジェクトでは、ユーザーが独自のBクラスを作成し、それらのカスタムクラスで動作するようにオーバーレイすることが欲しいだけです。ただし、私はbarに電話する必要はありません。むしろ、barを基本クラス(私が定義する)から呼び出させたいと思います。それが私のようにこれをやろうとする主な理由です。それは、私ができるかどうかを確認する。

すべてをクリアすることを希望します。ありがとうございました。

+0

可能な重複[なぜ我々はC++での仮想メソッドが必要なのでしょうか?](http://stackoverflow.com/questions/2391679/why-do-we-need-virtual-methods-in-c) –

+0

あなたの編集から、派生クラスに存在するデータメンバーへの完全なアクセスを提供する、 'virtual'メンバーから 'class A 'への正しい方法が正しいように見えます。このようなアクセスには、実行時の型情報などが含まれている可能性があります。 – Walter

答えて

2

私はこれがあなたのために働くだろうと思います。 まず、純粋な仮想メンバ関数call_barを定義し、それを基底クラスAで呼び出すことができます。実装には適切な型が必要ですが、CRTPを使用すると、ユーザークラスがそれを指定できます。

class A 
{ 
public: 
    virtual void call_bar() = 0; 
    virtual ~A() {} 
}; 

template <typename T> 
class B : public A 
{ 
public: 
    virtual void call_bar() override 
    { 
    bar(static_cast<T*>(this)); 
    } 
}; 

class C: public B<C> 
{ 
}; 
+0

このテクニックは間違いなく私にとってはうまくいくようです。私が抱えている唯一の問題は、 'A'オブジェクトのベクトルを作成しようとすると、コンパイラはテンプレートパラメータを指定する必要があることを私に伝えます。完全なエラーは、 'テンプレート引数1は無効です'という行にあります: 'typedef std :: vector a_list;'。 'std :: vector > a_list;'と言うと、このテクニックはまだ動作しますか? – AFlyingCar

+0

'A'はテンプレートではありません。' B'をスキップしましたか?ここでは、[Ideone](https://ideone.com/x58ml0)@AFlyingCar – Drek

+0

での使用例をご紹介します。私は私のプロジェクトに合うようにあなたのソリューションを少し修正しましたが、そうしてしまったので、誤って 'A'の代わりに' B'に気付かせました(気づかずに)。私は今それを修正しました。ご協力いただきありがとうございます。 – AFlyingCar

4

これは仮想メソッドの目的です。

Afoo()仮想メソッドを宣言してください。醜いキャストをする心配はありません。

また、Aに少なくとも1つの仮想関数があり、仮想デストラクタが実行する場合はdynamic_cast<>であなたの運を試すことができます。

3

C++では(動的)polymorphismがこのタイプのものです。

struct A { 
    virtual void foo() = 0; 
    virtual~A() {} 
}; 

struct B : A { 
    void foo() override; 
}; 

std::vector<std::unique_ptr<A>> vA; 
vA.emplace_back(new B); 
vA[0]->foo(); 

オブジェクトの実際の型はvA[0]によって指さ見つける必要はありません、virtual関数呼び出し機構(この場合B::foo()に)正しい関数を見つけます。 デストラクタclass Aに注意してください。派生オブジェクト(class B)がAunique_ptr<A>が保持する)へのポインタから正しく削除されることを保証します。もちろん

は、また、あなたがオブジェクトが特定の型で実際にあるかどうかをテストすることができますdynamic_cast<>、そこにある:

auto ptr = dynamic_cast<B*>(vA[0].get()); 
if(ptr) // object is a B 
    std::cout<<" have B"; 
私は私が必要な場合があります考えているソリューションは、何らかの形で決定することである
+1

これ以外の素晴らしい答えでは 'unique_ptr'の使い方が間違っていると思います。驚くべき副作用のため初心者に教えるものではありません。スマートポインタを使用する必要がある場合は、代わりに 'shared_ptr'を使用します。これは、ポインタが動作すると予想されるように動作するためです。私の+1はありません。 – Fozi

+1

私は上記の意見に同意しません。 'unique_ptr'は、動的に割り当てられたオブジェクトを保持するためにデフォルトで使うべきものです。所有しているポインタは問題にならないので、実際に複雑さが増すまで、 'shared_ptr'は過剰です。 – Quentin

+0

@Fozi私の思考は、Quentinのコメントのラインに沿ったものでした。私はあなたが言及している「驚くべき副作用」が何であるか分かりません。 IMHO、 'shared_ptr'は所有権が共有される場合にのみ有効です(そして、複数のそのようなポインタが1つのオブジェクトのために潜在的に作成されます)。これはここでは当てはまりません。 – Walter

0

それぞれのオブジェクトが実行時にある型であるため、バーに渡す前にキャストできます。

dynamic_castあなたが探しているものです。

class A 
{ 
public: 
    virtual ~A() {} 
}; 

class B: public A 
{ 
public: 
    void foo() { 
    printf("B::foo()\n"); 
    } 
}; 

... 

std::vector<A*> v; 
v.push_back(new B); 

... 

A *a = v.get(0); 
B *b = dynamic_cast<B*>(a); 
if (b) 
    bar(b); 
関連する問題