3

I have created a base class that provides a common signal for all its subclasses:

#include <QWidget>

namespace Dino {

/**
 * @brief Base class for all single-value settings editors
 *
 * Provides a valueChanged() signal that can be used to propagate changes to
 * values up to the MainWindow
 */
class TypeEditor : public QWidget
{
    Q_OBJECT
public:
    explicit TypeEditor(QWidget *parent = 0):QWidget(parent){}

signals:
    void valueChanged();    
};

} // namespace Dino

In a subclass, I want to have this signal available, but also define a more specific signal with the same name but different arguments:

#include "ui/typeeditor.h"

namespace Dino {

class BoolEditor : public TypeEditor
{
    Q_OBJECT
public:
    explicit BoolEditor(QWidget* parent = 0):TypeEditor(parent){}

signals:
    void valueChanged(bool value);

public slots:
    void setValue(bool value)
    {
        emit valueChanged(value);
        emit valueChanged();
    }
};

} // namespace Dino

The idea is that when only the base class type is known, the generalized signal can be used, which tells that there has been a change in the value. When the exact subclass type is known, another signal is available, which tells the new value.

Now, when I try to compile I get an error on the emit valueChanged() stating that there is no function called Dino::BoolEditor::valueChanged().

When I rename the signal in the base class to something else it works, so this seems to be a problem of overloading the signal. I would be interested in the reason for this. Is it some design requirement that I'm not aware of that prevents me from overloading a signal in a subclass, or am I just missing something in the code?

toster
  • 332
  • 4
  • 9

4 Answers4

3

Signal is just a protected function. You can't overload base class functions like that

See this question for more details

Community
  • 1
  • 1
spiritwolfform
  • 2,263
  • 15
  • 16
  • Thanks. I was not aware of that. Somehow something like this never happened to me before, even when not using Qt. I figured the compiler must notice that the base class function that takes no arguments is the only one that matches here. Stupid me for assuming more intelligence in the compiler than there is. Thanks for linking that other question. It has some insightful answers. – toster May 17 '13 at 10:59
2

This is overloading methods in C++. Try:

emit TypeEditor::valueChanged();
Amartel
  • 4,248
  • 2
  • 15
  • 21
  • Thanks. I did try that before, but figured the compiler must be intelligent enough to figure that out by itself. – toster May 17 '13 at 11:00
0

it is a problem of overloading the signal.

First, your issue is a C++one, not a Qt one. Then in your case,you cannot speak of overloading.

If you define in derived class a method with same name and signature than a base class method,then you are overloading. If you had b->valueChanged(), with this signal with no parameters defined in base class, here you would get no compile error.

When compiling your code, compiler looks fot a valueChanged() signal in closest scope, that is scope of B class. He finds a valueChanged(bool) and then checks argument list. Since there is no match, there is compile error.

kiriloff
  • 25,609
  • 37
  • 148
  • 229
  • Overloading only requires the same function name, not the same signature (http://en.wikipedia.org/wiki/Function_overloading). What you are referring to is overriding (http://en.wikipedia.org/wiki/Method_overriding). – toster May 22 '13 at 11:55
0

What you are doing is called "shadowing" or "hiding" a name. When the compiler does its magic to copy an inheritance hierarchy into a base class (I know that there is more to that, I'm just simplifying), it first looks in the current scope to see if there is something with the same name. If it can find a member with the same name (not the signature or type) as what you are looking for, it doesn't look any further, even if there are better candidates in the inheritance hierarchy!

So, how do you get around this? You can import the declaration from the parent class into the derived class with a using statement. (You can see more about this here.)

For example:

struct A {
    int f() { return 42; }
};

struct B : A {
    using A::f; // <- This is the magic line!
    int f(int n) { return 42 + n; }
};

That using A::f; statement in the derived class adds the f member from A into the current scope and now both functions are visible and can be used!

Here is a runnable example on ideone.

callyalater
  • 3,102
  • 8
  • 20
  • 27
  • I am sorry for contacting you this way (my comment isnt related to your input here). I came across a question you voted on in "triage" where you made the wrong choice. Please: study the help for triage carefully, to avoid putting items into the edit queue that don't belong there. I hope you see this as a chance to improve your voting. I am specifically talking about https://stackoverflow.com/review/triage/21072947. Feel free to drop me a comment in case you have further questions or feedback for me. If you give me a quick reply, I will immediately this comment here. – GhostCat Oct 09 '18 at 04:03