【问题标题】:Call method on subclass given pointer to superclass给定超类指针的子类调用方法
【发布时间】:2015-10-04 01:19:25
【问题描述】:

我有一组按钮:

buttons = new QButtonGroup();

button_0 = new MyButton("A", this);
button_1 = new MyButton("B", this);
button_2 = new MyButton("C", this);

MyButton 是一个 QPushButton,它继承了 QAbstractButton。一次可以选择组中的一个 MyButton。

MyButton::MyButton(const QString &text, QWidget *parent)
    : QPushButton(text, parent)
{
    this->setCheckable(true);
    this->setChecked(false);
}

MyButton 有一个增量方法。

void MyButton::increment()
{
    this->j++;
}

我想在当前选择的任何 MyButton 实例上调用 increment 方法。我可以在buttons 上调用一个方便的checkedButton() 方法,但它返回一个指向QAbstractButton 的指针。

我无法在指针或 QAbstractButton 上调用 incrementbuttons->checkedButton()->increment(); 产生 error: no member named 'increment' in 'QAbstractButton'。如何增加选定的 MyButton?

【问题讨论】:

    标签: c++ qt inheritance


    【解决方案1】:

    您只需要让编译器知道您使用的是MyButton* 而不是QAbstractButton*,这意味着强制转换。

    如果您知道指针是 MyButton*,那么您可以只执行 static_cast<MyButton*>(buttons->checkedButton())->increment(); 如果您不知道它是否是 MyButton*,那么您需要检查,这意味着类似这个:

    MyButton* temp = dynamic_cast<MyButton*>(buttons->checkedButton());
    
    if(temp != nullptr) temp->increment();
    

    编辑: SaZ has pointed out 认为 qobject_castdynamic_cast 更可取,因为:

    它不需要 RTTI 支持,并且可以跨动态库边界工作

    MyButton 已经继承自 QObject,但还有一个限定条件,它是用 Q_OBJECT 声明的。如果满足这两个条件,那么您可以简单地将dynamic_cast 替换为qobject_cast

    MyButton* temp = qobject_cast<MyButton*>(buttons->checkedButton());
    
    if(temp != nullptr) temp->increment();
    

    【讨论】:

    • 谢谢!我试图从 QAbstractButton 转换为 MyButton 而不是 QAbstractButton* 转换为 MyButton*。这应该会更好!
    • 通常,使用dynamic_cast 是糟糕设计的表现。一个例外 - 在带有 qobject_cast 的插槽中投射 sender()
    • @SaZ sender() 是一个很好的调用仅当此方法是从消息中调用的slot并且时未使用 lambda 调用消息。我会编辑。
    • 从我的角度来看,应该有一个带有虚拟increment方法的父类。因为基于真实对象类型编写逻辑会破坏多态性。
    • @SaZ 嗯...我同意您的说法“因为基于真实对象类型编写逻辑会破坏多态性”。但是我不确定层次结构中的另一个父级是答案,似乎应该发生的事情是他传递了一个实际的MyButton*而不是QAbstractButton*,但没有完整了解代码正在尝试什么完成我不知道这是否可能。
    【解决方案2】:

    请注意,对于QObject 派生类,您可以而且应该使用qobject_cast() 而不是动态转换。使用 Qt 元系统效率更高。

    此外,与动态转换不同,它在没有 RTTI 的情况下编译时也可以工作,也可以使用动态库。

    【讨论】:

      【解决方案3】:

      QAbstractButton 动态转换为MyButton 并调用increment()

      QAbstractButton* abstractButton = buttons->checkedButton();
      MyButton* myButton = dynamic_cast<MyButton*>(abstractButton);
      if (myButton)
      {
          myButton->increment();
      }
      

      【讨论】:

        【解决方案4】:

        为了完整起见,对于 Qt 程序,您还可以使用信号槽系统:如果 increment 被声明为 slot,那么这将起作用:

        QMetaObject::invokeMethod(abstractButton, "increment");
        

        【讨论】:

        • increment 方法的签名将被更改时 - 您将忘记更改代码中的所有此类字符串。这是一种不好的做法。
        • + 你会在 Qt 的输出中得到额外的警告。
        猜你喜欢
        • 2020-09-02
        • 2011-10-24
        • 2017-04-13
        • 2012-04-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多