插件代码中的通用基类

时间:2013-01-03 16:29:42

标签: c++ c++11

应用程序定义了3个要在插件中实现的接口。 Widget始终是基础。

// Application code...
class Widget {
    virtual void animate() = 0;
};

class BigWidget : public Widget {
};

class SmallWidget : public Widget {
};

每个接口实现都派生自NiceWidget,它提供了一些插件内部公共信息。

// Plug-in code...
class NiceWidget {
    // nice::Thing is only known in plug-in code.
    nice::Thing thing();
};

class NiceBigWidget : public NiceWidget, public BigWidget {
    void animate() override;
};

class NiceSmallWidget : public NiceWidget, public SmallWidget {
    void animate() override;
};
从应用程序代码调用

func。已知wid由此插件实现。因此,wid也是NiceWidgetfunc的目标是调用它的thing方法。

// Plugin-in code...
void func(Widget* wid) {
    // wid is either NiceBigWidget or NiceSmallWidget.
    auto castedBig = dynamic_cast<NiceBigWidget*>(wid);
    if (castedBig) {
        castedBig->thing().foo();
        return;
    }

    auto castedSmall = dynamic_cast<NiceSmallWidget*>(wid);
    if (castedSmall) {
        castedSmall->thing().foo();
        return;
    }

    assert(false);
}

但是,随着层次结构大小的增加,尝试将wid强制转换为每个Nice*会变得非常糟糕。那里有更好的解决方案吗?

2 个答案:

答案 0 :(得分:3)

首先:如果您知道wid始终是NiceWidget*,为什么不在func()中说出来?你根本不需要演员:

void func(NiceWidget* wid)
{
  wid->thing().foo();  // Done
}

即使您因任何原因无法更改功能签名,您也只需要一次演员:

void func(Widget* wid)
{
  NiceWidget* casted = dynamic_cast<NiceWidget*>(wid);
  if (casted)
    casted->thing().foo();
  else
    throw std::exception(); // Well, throw the right exception
}

当然,如果你认为对你的目的更好,你可以assert()而不是抛出异常。

在任何情况下,您只需要一个指向类的指针,该类定义您需要使用的函数(在本例中为thing()),而不是大多数派生类。如果您将覆盖派生类中的函数,请将其设置为虚拟,并且无论如何都要完成。

答案 1 :(得分:0)

如果您知道每个NiceWidget都是Widget,则应考虑从NiceWidget延长Widget

class Widget {
    virtual void animate() = 0;
};

class BigWidget : public Widget {
};

class SmallWidget : public Widget {
};

class NiceWidget : Widget{
    // nice::Thing is only known in plug-in code.
    nice::Thing thing();
};


class NiceBigWidget : public NiceWidget, public BigWidget {
    void animate() override;
};

class NiceSmallWidget : public NiceWidget, public SmallWidget {
    void animate() override;
};

还会有另一个名为The diamond problem的问题,可以使用虚拟扩展来解决

之后,从dynamic_castWidget

NiceWidget应该没问题