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
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,但如果你用明显的类型替换“自动”类型,它将是 C++98(如果有很多情况,我会使用宏)。

于 2013-02-21T12:52:15.703 回答
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
#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. 您只需要做一个,但每次您想使用新类型作为模板参数时dynamic_cast<>都不必更改,从而让您的代码尊重开放/封闭原则。Foo()

于 2013-02-21T13:49:17.960 回答
1

如何调用正确的 DoSomething 方法?

最好利用多态在 C++ 中的工作原理,而不是编写一些基于强制转换的调度函数。几个选择:

  • 在类中声明DoSomething为公共纯虚方法Base。该模板将提供实现。
  • 定义DoSomething为类中的公共非虚拟方法Base。该实现调用了一些私有的纯虚拟方法。模板再次提供了这个虚拟方法的实现。
于 2013-02-21T12:56:35.460 回答