Qaz
Qaz

Reputation: 1576

Call method on subclass given pointer to superclass

I have a set of buttons in a group:

buttons = new QButtonGroup();

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

MyButton is a QPushButton, which inherits QAbstractButton. One MyButton in the group can be selected at a time.

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

MyButton has an increment method.

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

I want to call the increment method on whichever MyButton instance is currently selected. There's a handy checkedButton() method that I can call on buttons, but that returns a pointer to a QAbstractButton.

I can't call increment on the pointer or the QAbstractButton. buttons->checkedButton()->increment(); yields error: no member named 'increment' in 'QAbstractButton'. How can I increment the selected MyButton?

Upvotes: 1

Views: 114

Answers (4)

Jonathan Mee
Jonathan Mee

Reputation: 38909

You just need to let the compiler know that you are using a MyButton* rather than a QAbstractButton*, and that means a cast.

If you know that the pointer is a MyButton* then you can just do a static_cast<MyButton*>(buttons->checkedButton())->increment(); If you don't know if its a MyButton* then you'll need to check, and that'll mean something like this:

MyButton* temp = dynamic_cast<MyButton*>(buttons->checkedButton());

if(temp != nullptr) temp->increment();

EDIT: SaZ has pointed out that qobject_cast is preferable to dynamic_cast because:

It doesn't require RTTI support and it works across dynamic library boundaries

MyButton already inherits from QObject, but there is one more qualification, that it is declared with Q_OBJECT. If both of these qualifications are met then you can simply replace the dynamic_cast with a qobject_cast:

MyButton* temp = qobject_cast<MyButton*>(buttons->checkedButton());

if(temp != nullptr) temp->increment();

Upvotes: 2

Matt
Matt

Reputation: 15081

For the sake of completeness, in the case of Qt program you may also make use of signal-slot system: if increment was declared to be a slot then this would work:

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

Upvotes: -1

dtech
dtech

Reputation: 49279

Note that in the case of QObject derived classes, you can and should use qobject_cast() instead of dynamic cast. It is more efficient by employing the Qt meta system.

Also, unlike the dynamic cast, it will work when compiling without RTTI, and with dynamic libraries as well.

Upvotes: 2

Lahiru Chandima
Lahiru Chandima

Reputation: 24068

Dynamic cast QAbstractButton to MyButton and call increment().

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

Upvotes: 1

Related Questions