0

这可能是一个愚蠢的问题,我怀疑我知道答案(不),因为我似乎在这里碰壁了。

鉴于我有一组从某个类派生的对象:

class BaseClass;
class DerivedA: public BaseClass;
class DerivedB: public BaseClass;
class DerivedC: public BaseClass;
std::vector<BaseClass> myCollection;

我想根据特定类的类型调用方法:

class Processor {
  void doSomething(DerivedA a, DerivedB b);
  void doSomething(DerivedA a, DerivedC c);
}

问题是,如果我访问集合中的各个项目并尝试调用“处理器”中的“doSomething”方法,它将无法决定使用哪种方法(afaik)。所以我的问题是:有没有办法用正确的派生类型来获取集合中的项目?

4

2 回答 2

2

如果您要保持doSomething方法不变,这就是所谓的多重分派,目前 C++ 不支持。

如果它是一个虚成员函数,BaseClass那么是的,它将是在它被调用的对象上运行磨机 C++ 多态性,但它仍然不会自动推断争论的类型。

为了解决这个问题,您可以执行之前链接中建议的操作

void collideWith(Thing& other) {
     // dynamic_cast to a pointer type returns NULL if the cast fails
     // (dynamic_cast to a reference type would throw an exception on failure)
     if (Asteroid* asteroid = dynamic_cast<Asteroid*>(&other)) {
         // handle Asteroid-Asteroid collision
     } else if (Spaceship* spaceship = dynamic_cast<Spaceship*>(&other)) {
         // handle Asteroid-Spaceship collision
     } else {
         // default collision handling here
     }
 }

基本上保持转换为各种可能的派生类,直到一个工作并适当地调用其中一种方法(无需特别努力,因为编译器知道您要转换为哪种类型)。

重要提示:正如@WhozCraig 指出的那样,您的向量需要保存指针以避免对象切片并使整个问题变得毫无意义。

于 2012-12-27T15:37:12.310 回答
1

好的,是的,您应该如上所述使用多态性。如果您的函数需要处理 2 个对象,尽管它变得非常复杂。

如果派生形成一个有限的集合并且彼此了解,则可以使用双重调度。它并不完美,但它解决了这种特殊情况。

class DerivedA;
class DerivedB;
class DerivedC;

class BaseClass
{
 public:
     virtual ~BaseClass();

     virtual void doSomethingWithBase( BaseClass & b2 ) = 0;
     virtual void doSomethingWithDerivedA( DerivedA & da ) = 0;
     virtual void doSomethingWithDerivedB( DerivedB & db ) = 0;
     virtual void doSomethingWithDerivedC( DerivedC & dc ) = 0;
};

class DerivedA : public BaseClass
{
   public:

      void doSomethingWithBase( BaseClass & b2 )
      {
           b2.doSomethingWithDerivedA( *this );
      }

      void doSomethingWithDerivedA( DerivedA & da )
      {
           // implement for two DerivedA objects
      }

      void doSomethingWithDerivedB( DerivedB & db )
      {
           // implement for an A and B
      }

      void doSomethingWithDerivedC( DerivedC & dc )
      {
          // implement for an A and C
      }
 };

 // implement DerivedB to call doSomethingWithDerivedB on its parameter
 // implement DerivedC to call doSomethingWithDerivedC on its parameter.

你明白了。从你打电话的地方你不需要知道你有哪两种类型,你也不需要实际查找。但是,如果您添加了更多的实现,您将需要编辑大量代码,并且可能会考虑使用某种查找表。

如果你需要一个类来定义自己,你可以使用某种虚拟 id。

  class BaseClass
  {
      public:
         virtual int id() const = 0;
  };

然后让类显示它们的 id 并根据这些 id 在表中找到处理这两个对象的处理程序。id 不必是整数,它们可以是字符串,这样更容易避免命名冲突,这比不知道其派生类或它们彼此认识的基类的双重调度方法具有优势,并且是可扩展的。您也不必处理每一对。

于 2012-12-27T15:34:39.723 回答