2017-09-07 5 views
17

仮想関数に未知のタイプを渡す:C++、私はC++で書いていると私は純粋仮想関数に(実行時にのみ知られている)未知のタイプを渡したい

DoSomethingが実装され
virtual void DoSomething(??? data); 

派生クラスの純粋仮想関数の

私はテンプレートを使用する計画が、それは仮想関数を回し、テンプレートが一緒に動作しないよう:Can a C++ class member function template be virtual?

私は関数に渡すすべてのクラスの基本クラスを使用しないようにしたい(objectのようなものをC#で)。あなたがtype erasureを必要とし、事前

+1

は、あなたがより具体的に説明してくださいすることができますがあなたはVisitorパターンを使用して興味がある可能性があり

?どのように関数内のデータを使用しますか?データのタイプの要件は何ですか?例えば。ご存じのクラスがいくつかありますか、または特定のメソッドなどを持つクラスを受け入れる予定ですか? – bolov

+1

あなたの質問はちょっと狭められる必要があります。タイプの範囲を知っていますか?自動的に推論されますか?最も単純な答えは "void *を使う"でしょう。ストーリーテラーの方が良い答えかもしれません。それはあなたのユースケースに左右されます。 –

+0

'doSomething'をキャスティングすることなく同じ結果を達成する可能性があるのなら、私は不思議で、答えを見ています。 'doSomething'をテンプレートにすることなく型を何らかの方法でカプセル化し、' decltype'、すなわち仮想ファクトリメソッドの種類を取り出すことのようなもの... – perencia

答えて

18

感謝。これの一例は汎用目的boost::any(およびC++ 17ではstd::any)です。

virtual void DoSomething(boost::any const& data); 

し、各サブクラスは、それが期待したデータを取得するために安全any_castを試みることができます。あなたが求める行動の範囲がより制約の場合

void DoSomething(boost::any const& data) { 
    auto p = any_cast<std::string>(&data); 

    if(p) { 
    // do something with the string pointer we extracted 
    } 
} 

はもちろん、独自の型消去の抽象化をロールアウトすることができます。あなたはブーストを使用しない場合はそのような

0

何か?:

class Foo 
{ 
    virtual ~Foo() = 0; 
}; 

template <typename T> 
class Bar : public Foo 
{ 
    T object; 
} 

... 

virtual void DoSomething(Foo* data) 
{ 
    Bar<int>* temp = dynamic_cast<Bar<int>*>(data); 
    if (temp) 
     std::count<<temp->object; 
} 
+6

'Foo'は少なくとも1つの仮想メンバ関数(おそらくデストラクタ)を必要とします。そうでなければ' dynamic_cast'は動作しません。 – Angew

+0

'関数に渡すすべてのクラス(C#のオブジェクトのようなもの)に基本クラスを使用しないようにしたい ' – perencia

+0

これは関数に渡される各オブジェクトの基本クラスを必要とせず、バー。これは技術的には「オブジェクトに渡された」ものですが、OPが意味するものではありそうにありません。 – AzCopey

1

/任意のC++ 17、ベースクラスから「doSometing」関数のパラメータを導出検討し、それらへの動的なキャストを行います正しいクラスオブジェクト。この場合、実行時に有効なポインタがあることを確認できます。

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

template <typename T> 
struct specificParam:param{ 
    specificParam(T p):param(p){} 
    T param; 
}; 


class Foo 
{ 
public: 
    virtual void doSomething(param* data) = 0; 
}; 

template <typename T> 
class Bar : public Foo 
{ 
public: 
    virtual void doSomething(param* data){ 
     specificParam<T> *p = dynamic_cast<specificParam<T> *>(data); 

     if (p != nullptr){ 
      std::cout<<"Bar got:" << p->param << "\n"; 
     } 
     else { 
      std::cout<<"Bar: parameter type error.\n"; 
     } 
    } 
}; 

int main(){ 
    Bar<char> obj1; 
    Bar<int> obj2; 
    Bar<float> obj3; 

    specificParam<char> t1('a'); 
    specificParam<int> t2(1); 
    specificParam<float> t3(2.2); 

    obj1.doSomething(&t1); //Bar got:a 
    obj2.doSomething(&t2); //Bar got:1 
    obj3.doSomething(&t3); //Bar got:2.2 

    // trying to access int object with float parameter 
    obj2.doSomething(&t3); //Bar: parameter type error. 
} 

最も簡単な(しかし安全ではない!)の方法は、Type-消去が唯一の可能性ではありませんvoid *型のポインタ+静的キャスト

class Foo 
{ 
public: 
    virtual void doSomething(void* data) = 0; 
}; 

template <typename T> 
class Bar:public Foo 
{ 
public: 
    virtual void doSomething(void* data){ 
     T* pData = static_cast<T*>(data); 
     std::cout<<"Bar1 got:" << *pData << "\n"; 
    } 
}; 

int main(){ 

    Bar<char> obj1; 
    Bar<int> obj2; 
    Bar<float> obj3; 

    char c = 'a'; 
    int i = 1; 
    float f = 2.2; 

    obj1.doSomething(&c); // Bar1 got:a 
    obj2.doSomething(&i); // Bar1 got:1 
    obj3.doSomething(&f); // Bar1 got:2.2 

    //obj2.doSomething(&c); // Very bad!!!  
} 
1

を使用することです。引数としてのstd ::バリアントを取ると、あなたが実装したいテンプレートコード含むラムダでそれを参照してください:

virtual void doSomething(std::variant<int,float/*,...*/> data) 
    { 
    visit([=](auto v){/*...*/;},data); 
    } 
関連する問題