从基类调用指定的方法

时间:2016-04-04 16:25:09

标签: c++ c++11 polymorphism

不确定如何解释它,所以我将提供一个显示我的问题的代码示例:

class Base {
public:
  Base() = default;
  ~Base() = default;

  virtual void stuff(std::shared_ptr<Base> b) = 0;
};

class DerivedA : public Base {
public:
  DerivedA() = default;
  ~DerivedA() = default;

  void stuff(std::shared_ptr<Base> b) {
    std::cout << "stuff Base"
              << "\n";
  }
};

class DerivedB : public Base {
public:
  DerivedB() = default;
  ~DerivedB() = default;

  void stuff(std::shared_ptr<Base> b) {
    std::cout << "stuff Base"
              << "\n";
  }
  void stuff(std::shared_ptr<DerivedA> b) {
    std::cout << "stuff Derived"
              << "\n";
  }
};

int main(int argc, char *argv[]) {
  std::shared_ptr<Base> b1(new DerivedA());
  std::shared_ptr<Base> b2(new DerivedB());

  b1->stuff(b2);
  b2->stuff(b1);
  return 0;
}

输出将是:

stuff Base
stuff Base

现在,我想不可能调用派生方法,因为它在基类中不存在。

我的问题是:有没有办法使用基类调用stuff(std::shared_ptr<DerivedA> b)

[编辑]

我已经考虑过访客模式(应该说出来并且更具体)。

我的类代表实体,我必须检查它们之间的冲突。然而,A&amp; A之间的碰撞B将具有与B&amp; B之间不同的效果。下进行。

我同意它会起作用,但这意味着我必须定义大量的方法。

有更优雅的方式吗?

提前致谢。

3 个答案:

答案 0 :(得分:1)

My question is: Is there a way to call stuff(std::shared_ptr<DerivedA> b) using the base class ?

No, because the Base class interface doesn't implement the method you want to call. Even though the Base class pointer is referring to a DerivedB object, and through poilformism you can resolve the method with the respect to the type of the object pointed by the pointer (i.e. DerivedB), you can only call the method defined in the Base class. Therefore, you cannot call stuff(std::shared_ptr<DerivedA> b) using a Base pointer that points to a DerivedB object.

For example:

 std::shared_ptr<Base> b1(new DerivedA());
  std::shared_ptr<Base> b2(new DerivedB());
  std::shared_ptr<DerivedA> a1(new DerivedA());
  std::shared_ptr<DerivedB> bb1(new DerivedB());

  b1->stuff(b2);
  b2->stuff(b1);
  b2->stuff(a1); // b2 is the only class that implement stuff(std::shared_ptr<DerivedA> b)
  bb1->stuff(a1)

output:

stuff Base
stuff Base
stuff Base
stuff Derived
stuff Base

答案 1 :(得分:1)

What you are looking for is commonly called multiple dispatch, or a multimethod. There is no direct language support for this in C++, but you can explicitly implement it yourself. Basically, you have one virtual function which dispatches to another virtual function with a concrete object:

struct DerivedA;
struct DerivedB;

struct Base {
    virtual ~Base() = default;
    virtual void stuff(shared_ptr<Base> ) = 0;

    virtual void dispatch_stuff(Base& ) = 0;
    virtual void dispatch_stuff(DerivedA& p) { return dispatch_stuff(static_cast<Base&>(p)); }
    virtual void dispatch_stuff(DerivedB& p) { return dispatch_stuff(static_cast<Base&>(p)); }

struct DerivedA : Base {
    void stuff(shared_ptr<Base> rhs) override {
        rhs->dispatch_stuff(*this);
    }

    void dispatch_stuff(Base& ) { /* default */ }
    void dispatch_stuff(DerivedA& ) { /* specific A-A stuff */ }
};

This way:

b1->stuff(b2); // calls b2->dispatch_stuff(DerivedA& )
b2->stuff(b1); // calls b1->dispatch_stuff(DerivedB& )

答案 2 :(得分:1)

The problem you are trying to solve is called the double dispatch problem, which means you're trying to invoke a behaviour depending on the concrete type of two objects. Looking up this term on google or here may yield you some interesting results.

First thing, one way or another, you're going to have to write a lot of functions since if you have N different types there are NN possible pairings. (NN/2 if order doesn't matter, which is probably the case in your collision scenario).

The visitor pattern is one of the canonical solutions to the double dispatch problem.

There are others, depending on what matters to you. Off the top of my head, for example, if the number of subtypes is limited and known at compile time, you can for example have an index for each type and a 2D array of function pointers to call (not very elegant nor very object oriented but quite efficient in terms of performance).

If you fear that the number of functions is likely to cause code duplication you can always factor the code inside a function, or a class ( something like CollisionPairBehavior ).