107

我的 GUI 项目Qt有很多“配置页面”类,它们都直接继承自QWidget.

最近,我意识到所有这些类共享 2 个公共插槽(loadSettings()saveSettings())。

对此,我有两个问题:

  • BaseConfigurationPage用这两个插槽作为虚拟纯方法编写一个中间基抽象类(让我们命名)是否有意义?(每个可能的配置页面都会有这两种方法,所以我会说“是”)
  • 在我对代码进行重大更改之前(如果必须):Qt 是否支持虚拟纯插槽?有什么我应该注意的吗?

这是一个描述所有内容的代码示例:

class BaseConfigurationPage : public QWidget
{
  // Some constructor and other methods, irrelevant here.

  public slots:

    virtual void loadSettings() = 0;
    virtual void saveSettings() = 0;
};

class GeneralConfigurationPage : public BaseConfigurationPage
{
  // Some constructor and other methods, irrelevant here.

  public slots:

    void loadSettings();
    void saveSettings();
};
4

3 回答 3

174

是的,就像常规的 c++ 纯虚方法一样。MOC 生成的代码确实调用了纯虚拟插槽,但这没关系,因为无论如何都无法实例化基类......

同样,就像常规的 c++ 纯虚方法一样,在给定方法实现之前,不能实例化该类。

一件事:在子类中,您实际上不需要将覆盖的方法标记为槽。首先,它们已经被实现为基类中的插槽。其次,您只是在为 MOC 和编译器创建更多工作,因为您添加了(微小的)更多代码。微不足道,但无论如何。

所以,去吧。。

于 2010-06-08T14:43:55.643 回答
2

仅 BaseConfigurationPage 中的插槽

class BaseConfigurationPage : public QWidget
{
  // Some constructor and other methods, irrelevant here.

  public slots:

    virtual void loadSettings() = 0;
    virtual void saveSettings() = 0;
};

class GeneralConfigurationPage : public BaseConfigurationPage
{
  // Some constructor and other methods, irrelevant here.

    void loadSettings();
    void saveSettings();
};
于 2013-11-22T08:20:33.447 回答
0

其他人已经解释了虚拟、继承和插槽的机制,但我想我会回到这个部分或问题:

编写一个中间基抽象类是否有意义......将这两个插槽作为虚拟纯方法?

我会说,只有当您使用该抽象时,或者换句话说,如果您有在一个或多个BaseConfigurationPages 上运行而不关心实际类型的代码,这才有意义。

假设您的对话框代码非常灵活,并且包含一个std::vector<BaseConfigurationPage*> m_pages. 然后,您的加载代码可能如下所示。在这种情况下,抽象基类是有意义的。

void MyWizard::loadSettings()
{
    for(auto * page : m_pages)
    {
        page->loadSettings();
    }
}

但是,另一方面,假设您的对话实际上是相当静态的并且具有IntroPage * m_introPage; CustomerPage * m_customerPage; ProductPage * m_productPage;. 然后,您的加载代码可能如下所示。

void MyWizard::loadSettings()
{
    m_introPage->loadSettings();
    m_customerPage->loadSettings();
    m_productPage->loadSettings();
}

在这种情况下,BaseConfigurationPage你绝对没有任何收获。它增加了复杂性并增加了代码行,但没有增加表达能力,也不能保证正确性。

如果没有更多的上下文,这两种选择都不一定更好。

作为学生或新程序员,我们通常被教导识别和抽象出重复,但这实际上是一种简化。我们应该寻找有价值的抽象。重复可能暗示需要抽象,或者它可能只是有时实现具有模式的标志。仅仅因为注意到一种模式而引入抽象是一个很常见的设计陷阱。

的设计DolphinShark外观的设计很相似。人们可能很想插入一个TorpedoShapedSwimmer基类来捕获这些共性,但是这种抽象是否提供了价值,或者它实际上是否会在稍后实现breathe()“lactate() orgrowSkeleton()”时增加不必要的摩擦?

我意识到这是对基于一些简单示例代码的子问题的长篇大论,但我最近在工作中多次遇到这种模式:基类只捕获重复而不增加价值,但会妨碍未来变化。

于 2021-06-11T12:28:35.637 回答