2

Foo正しい関数にディスパッチする関数を実装するにはどうすればよいですか?

次のコードは問題を再現し、コメントでいくつかの追加情報を取得しました。

#include <string>

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

template<typename T>
class Derived : public Base 
{};

void DoSomething(const Derived<std::string> &){};
void DoSomething(const Derived<int> &){};

void Foo(Base *test)
{
    // How to call correct DoSomething method?
    // (I can't change class Base, but I know that test points to some instance of class Derived)?
    // if(test points to an instance of Derived<int>)
    //     call void DoSomething(const Derived<int> &){};
    // else if(test points to an instance of Derived<std::string>)
    //     call void DoSomething(const Derived<std::string> &){};
}

int main(int argc, char* argv[])
{
    Base *test = new Derived<int>;

    Foo(test);

    delete test;
    return 0;
}
4

4 に答える 4

3

OOに関しては、派生クラス自体だけがそれが誰であり、何をすべきかを知っています。

#include <string>
class Base {}
class Mid : public Base
{
public:
    virtual void DoSomething() = 0;
};

template<typename T>
class Derived : public Mid 
{
public:
    virtual void DoSomething() {}
};

template<> void Derived<std::string>::DoSomething(){}
template<> void Derived<int>::DoSomething(){}

void Foo(Base *test)
{
    dynamic_cast<Mid*>(test)->DoSomething(); //TODO check the return of dynamic_cast
}

int main(int argc, char* argv[])
{
    Base *test = new Derived<int>;

    Foo(test);

    delete test;
    return 0;
}
于 2013-02-21T13:01:38.633 に答える
3
void Foo(Base *test)
{
  if (auto* p = dynamic_cast<Derived<int>*>(test))
    DoSomething(*p);
  else if (auto* p = dynamic_cast<Derived<string>*>(test))
    DoSomething(*p);
  else
    throw runtime_error("oops");
}

タイプが正しくない場合、dynamic_castはnullptrを返すため、これは機能します。上記のコードはC++11ですが、「auto」タイプを明白なタイプに置き換えるとC ++ 98になります(多くの場合はマクロを使用します)。

于 2013-02-21T12:52:15.703 に答える
3
#include <string>

class Base  
{};

class DerivedBase : public Base 
{
public:
    virtual void DoSomething() = 0;
};

template<typename T>
class Derived : public DerivedBase
{};

void Foo(Base *test)
{
   if (auto* p = dynamic_cast<DerivedBase*>(test))
       p->DoSomething();
   else
       throw runtime_error("oops");
}

int main(int argc, char* argv[])
{
   Base *test = new Derived<int>;

   Foo(test);

   delete test;
   return 0;
}

中間クラスを宣言すれば、そのままポリモーフィズムを利用できますBase。1 つだけ実行する必要がありますが、新しい型をテンプレート引数として使用するたびdynamic_cast<>に変更する必要はありません。したがって、コードで Open/Closed Principle を尊重します。Foo()

于 2013-02-21T13:49:17.960 に答える
1

正しい DoSomething メソッドを呼び出すには?

キャストに基づいて何らかのディスパッチ関数を作成するよりも、C++ でポリモーフィズムがどのように機能するかを利用する方がはるかに優れています。いくつかの代替手段:

  • DoSomethingclass で public pure virtual メソッドとして宣言しBaseます。テンプレートは実装を提供します。
  • DoSomethingclass で public 非仮想メソッドとして定義しBaseます。実装は、いくつかのプライベートな純粋仮想メソッドを呼び出します。テンプレートは、この仮想メソッドの実装を再び提供します。
于 2013-02-21T12:56:35.460 に答える