Qt是否支持虚拟纯插槽?

时间:2010-06-08 14:27:22

标签: c++ qt inheritance signals-slots

Qt中的我的GUI项目有很多“配置页面”类,它们都直接从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();
};

3 个答案:

答案 0 :(得分:148)

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

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

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

所以,去吧..

答案 1 :(得分:0)

只有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();
};

答案 2 :(得分:0)

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

<块引用>

用这两个插槽作为虚拟纯方法编写一个中间基础抽象类有意义吗?

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

假设您的对话代码非常灵活并且包含 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 绝对不会给您带来任何好处。它增加了复杂性并增加了代码行,但没有增加表达能力,也不能保证正确性。

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

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

Dolphin 的设计和 Shark 的设计看起来很相似。人们可能会想插入一个 TorpedoShapedSwimmer 基类来捕获这些共性,但是这种抽象是否提供了价值,或者在以后实现 breathe(), 'lactate(){ 时实际上会增加不必要的摩擦{1}}growSkeleton()`?

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