从基类调用指定的方法

Call specified method from base class

本文关键字:方法 基类 调用      更新时间:2023-10-16

不知道如何很好地解释它,所以我只提供一个显示我的问题的代码示例:

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&B将具有不同于B&C.

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

有更优雅的方法吗?

提前谢谢。

您要查找的通常称为多重调度或多重方法。C++中没有直接的语言支持,但您可以自己显式地实现它。基本上,您有一个虚拟函数,该函数将分派给另一个具有具体对象的虚拟函数:

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 */ }
};

这样:

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

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

不,因为Base类接口没有实现您要调用的方法。即使Base类指针引用的是DerivedB对象,并且通过poilformism,您可以根据指针指向的对象类型(即DerivedB)来解析方法,但您只能调用Base类中定义的方法。因此,不能使用指向DerivedB对象的Base指针来调用stuff(std::shared_ptr<DerivedA> b)

例如:

 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)

输出:

stuff Base
stuff Base
stuff Base
stuff Derived
stuff Base

您试图解决的问题称为双重调度问题,这意味着您试图根据两个对象的具体类型调用行为。在谷歌或这里查找这个术语可能会给你带来一些有趣的结果。

首先,不管怎样,你必须写很多函数,因为如果你有N个不同的类型,就有N个可能的配对。(如果顺序无关紧要,则NN/2,这可能是碰撞场景中的情况)。

访问者模式是双重调度问题的典型解决方案之一。

还有其他的,这取决于对你来说重要的是什么。例如,在我的脑海中,如果子类型的数量是有限的,并且在编译时是已知的,那么例如,您可以为每种类型都有一个索引和一个要调用的函数指针的2D数组(既不太优雅,也不太面向对象,但在性能方面相当高效)。

如果您担心函数的数量可能会导致代码重复,您可以始终将函数或类(类似CollisionPairBehavior)中的代码考虑在内。