【问题标题】:C++, abstract class and inheritanceC++、抽象类和继承
【发布时间】:2013-06-10 19:49:05
【问题描述】:

我正在尝试两个两个处理类实例。 我有一个包含 doStuff 方法的抽象基类(此处为 IBase)。 此方法将在扩展类中被覆盖,以便处理所有其他已定义的类。

这是我正在构建的图书馆的一部分。我希望库用户编写 Base 对象。每个 Base 类都需要通过 doStuff 方法与另一个 Base 对象进行交互。需要容器来处理多个 Base 对象。

这不是我第一次遇到这个问题,但我不记得上次我是怎么做的。这种类可以用于很多事情。在这里,它是一个碰撞检测系统。 IBase 代表一个抽象的 HitBox,Container 代表发生碰撞的场景。在这种情况下,Container::process 检查命中框之间的转换,Container::process 用于实现优化算法(四叉树,...)。

我以这种方式构建了这些类:

class IBase {
    public:
        virtual void doStuff(IBase* base) = 0;
}

class Base {
    public:
        virtual void doStuff(Base* base) {
            foobar();
        }
        virtual void doStuff(IBase* base) {
            // irrelevant
        }
}

class Container {
    public:
        void process() {
            for (std::list<IBase*>::iterator it=base_list.begin() ; it!=base_list.end() ; it++) {
                for (std::list<IBase*>::itarator jt=std::next(it) ; jt!=base_list.end() ; jt++) {
                    (*it)->doStuff(*jt);
                }
            }
        }
    private:
        std::list<Ibase*> base_list;
}

但在循环中,当使用两个 Base 对象时,我无法达到 void Base::doStuff(Base*)。 我只能调用 Base::doStuff(IBase*) 这不是我想要的。

这有什么帮助吗?我理解这个问题,但我看不到解决方案。这是处理它的好方法还是我需要重新考虑我的架构?你会怎么做?我认为这样的问题必须存在设计模式,但我没有找到合适的。

谢谢

【问题讨论】:

  • 我在 process() 中看不到任何 Base 对象。我错过了什么吗?
  • 您似乎正在尝试创建一个包含 Base* 对象列表(或指向从 IBase 派生的对象的指针)的容器,对吗?然后遍历列表并调用多态 doStuff ?你应该能够做到这一点,只需将你的虚拟 doStuff() 声明为 public(或让 Container 成为 IBase 的朋友)
  • 我闻到了 XY problem 的味道。你真正想做什么?
  • 看起来你真的想要double-dispatch,有时实现为Visitor Pattern

标签: c++ inheritance abstract


【解决方案1】:

C++ 不支持参数的逆变。另见Why is there no parameter contra-variance for overriding?

您最好从doStuff(IBase* base) 正文中显式调用doStuff(Base* base)

【讨论】:

  • 这个。另外,将 doStuff() 公开。
【解决方案2】:

当从 *it*jt 取消引用时,您的对象被引用为 IBase 对象,而不是 Base 对象。这意味着只能调用来自IBase 的方法。

你的虚拟方法:

virtual void doStuff(Base* base) { ... }

没有覆盖任何东西。它正在创建一个 new 虚拟方法,只能从 Base 向下访问。当您从 IBase 指针调用 doStuff 时,它会调用:

virtual void doStuff(IBase* base) { ... }

IBase中定义的签名匹配。

如果你想执行你的foobar函数,你应该在base基于覆盖doStuff时做一些检查,一旦你确定它是安全的,将它转换为Base*,然后根据需要使用它。

virtual void doStuff(IBase* base) {
  // not irrelevant
  if (base->isBase()) 
  {
    foobar();
  }
}

最后,如前所述,公开doStuff

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-29
    • 1970-01-01
    • 2017-01-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多