Qt: inherited signal not recognized in subclass - c++

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?

Signal is just a protected function. You can't overload base class functions like that
See this question for more details

This is overloading methods in C++. Try:
emit TypeEditor::valueChanged();

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.

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.

Related

Why are my overloaded functions not seen by a subclass

I have a base class Base which provides a series of load functions, which read saved settings from a file. For example
void Base::load(QWidget *w);
virtual void Base::load(QTableWidget *t); // note this is declared virtual
void Base::load(QLineEdit *le);
Where Base::load(QWidget *w) will typically be called by a subclass on a high level widget. That routine will find the child widgets of the input widget (by type), and call the appropriate load routine on those. The overloading works as expected.
So in a subclass OkSubClass, I typically do a load like this:
void OkSubClass::load(void)
{
load(myMainWidget);
load(myOtherHighLevelWidget);
}
All is good - anything that is a child of either widget gets loaded.
Now I have a subclass of Base which needs to load things for a table slightly differently. It declares
virtual void ProblemSubClass::load(QTableWidget *t) ;
I also have some widgets used by this class that inherit a form class; e.g.
class myWidget: public QWidget, public MyForm { ... };
and ProblemSubClass has a member variable
myWidget *_myMainWidget;
now in the routine ProblemSubClass::load(void), I try to do the following:
ProblemSubClass::load(void)
{
load(_myMainWidget);
}
it complains that it can't convert _myMainWidget to a QTableWidget . Which surprises me, because I thought that ProblemSubClass should be able to see the load(QWidget) member function.
If I directly call the base class function, it works.
ProblemSubClass::load(void)
{
Base::load(_myMainWidget);
}
But I don't understand why it doesn't if I don't. Please enlighten me!
Unless you write using Base::load; somewhere in the declaration of the child class, that child class will not be able to see the other load functions declared in the base class.
It's one of those parts of C++ that appears odd at first.

Virtual Qt signal?

Whilst reviewing some Qt C++ code I came across this:
class Foo
{
Q_OBJECT
signals:
virtual void someSignal(const QString& str, int n)
{
Q_UNUSED(str);
Q_UNUSED(n);
}
...
};
Now, Qt signals cannot have a body so I'm surprised this even compiles (perhaps because the body is effectively empty). I also don't see the point of making a signal virtual as ... it can't have a body so how can it be overridden?
Am I missing something here or is this a valid code smell?
That looks smelly to me.
It's valid to declare a signal in a base class and then emit it from a derived class, e.g.
class MyBase : public QObject
{
Q_OBJECT
// ...
signals:
void somethingHappened();
};
class MyDerived : public MyBase
{
Q_OBJECT
// ...
void doSomething();
};
void MyDerived::doSomething()
{
// ....
emit somethingHappened();
}
Maybe that's what the declaration in the question was meant to achieve.
Strictly C++ speaking it's normal it compiles, given signal is a macro for protected and Q_UNUSED is a cast to void.
But you should get an error when running moc which precisely creates the implementation of the methods declared as signals.
Qt signals are not allowed to be (pure) virtual. See comments to this bug - https://bugreports.qt.io/browse/QTBUG-41004
TL;DR: I don't know what the code was meant to do, but it's wrong (not merely smelling wrong, it's prima facie invalid). Signal implementations are always meant to be generated by moc. The body of the signal should be removed.
For the code to work, it should do all three: compile, get past moc, and link. It is true that your code does compile - the C++ compiler has no reason not to. But it won't pass through moc nor will it link.
Although perhaps moc didn't detect some of it back in 2010, here's how moc acts today:
a) moc doesn't allow signal definitions in class bodies, with the diagnostic Error: Not a signal declaration. So class X { Q_SIGNAL void s() {} }; triggers it, but class X { Q_SIGNAL void s(); }; void X::s() {} won't.
b) moc doesn't allow a Q_OBJECT macro in a class not deriving from QObject, with the diagnostic Error: Class contains Q_OBJECT macro but does not inherit from QObject.
Since it doesn't make any sense to talk about signals in classes that don't derive from QObject, let's assume that the code really looked as follows:
class Foo : public QObject
{
Q_OBJECT
signals:
virtual void someSignal(const QString&, int);
};
void Foo::someSignal(const QString& str, int n)
{
Q_UNUSED(str);
Q_UNUSED(n);
}
This will get past moc and will compile, but it won't link. The linker will issue a diagnostic for multiple declaration of Foo::someSignal. There's one definition in this file, and another in the moc-generated source.

Issues with Partial Class Function Overrides in C++

Is there any issue with partially overriding a set of virtual functions defined by a base class?
My compiler provides the following warning:
overloaded virtual function "MyBaseClass::setValue" is only partially overridden in class "MyDerivedClass".
The classes look like this:
class MyBaseClass
{
public:
virtual void setValue(int);
virtual void setValue(SpecialType*);
}
class MyDerivedClass : public MyBaseClass
{
public:
virtual void setValue(int);
}
The easy way to get rid of this warning is to use different names for the base functions, but I wanted to know if there was any compelling reason to fix this specific warning. I do not believe this violates the C++ standard. My guess is that it's to warn a programmer that they may have forgotten to implement the behavior for all possible input types. In our case, it is intentional to exclude some of the specific types.
Would you discourage suppressing this warning altogether?
The override for setValue(int) hides setValue(SpecialType*) of the base class (see the C++ FAQ Lite), so if you try to call setValue(new SpecialType()) you will get an error.
You can avoid this by adding a using directive to the derived class that "imports" the overloads from the base class:
class MyDerivedClass : public MyBaseClass
{
public:
using MyBaseClass::setValue;
virtual void setValue(int);
};
The warning is correct, it's called "name hiding". A variable of type MyDerivedClass cannot call setValue(SpecialType*).
Now I'm going to blatantly rip off someone else's blog:
Overloading and name hiding in C++
In a phone conversation with Brad last night, he told me about a strange problem he's encountered in his new C++ job. Granted, it's probably no big deal to people with extensive C++ experience, but to those of us who live in managed code worlds, this seemed strange.
In C++, when you have a class with an overloaded method (member function, whatever you want to call it), and you then extend and override that method, you must override all of the overloaded methods.
I understand the case where you have changed a method signature in a child class, thereby invalidating the established interface. In this case, though, it seems counterintuitive, since you're not changing the interface, but selectively overriding. Which is different.
For example:
class FirstClass
{
public:
virtual void MethodA (int);
virtual void MethodA (int, int);
};
void FirstClass::MethodA (int i)
{
std::cout << "ONE!!\n";
}
void FirstClass::MethodA (int i, int j)
{
std::cout << "TWO!!\n";
}
Simple class here with two methods (or one overloaded method). You want to override the two-parameter version, so you continue with the following:
class SecondClass : public FirstClass
{
public:
void MethodA (int);
};
void SecondClass::MethodA (int i)
{
std::cout << "THREE!!\n";
}
Now, when you use an instance of SecondClass, most Java or C# programmers might assume you can call:
int main ()
{
SecondClass a;
a.MethodA (1);
a.MethodA (1, 1);
}
However, the second call won't work, since the two-parameter MethodA is not visible. You can get a pointer and up-cast to FirstClass, but your SecondClass instance doesn't inherit the non-overridden methods directly.
It's clear that the compiler wants to warn you: you created a subclass that behaves differently when giving it an int, but you didn't change it's behavior when giving it a SpecialType*.
Although this might be the intention, it is very very possible that the changed behavior is also needed for the other overloaded virtual functions.
I wish the compiler had warned me harder, the time I ignored it! My overridden method turned out to compile and work well in my scenario, but some other scenario's went really wrong due to the overload not being overridden.
Think twice before you disable that warning!
If you want the original behavior kept, it's easy to just call the parent function:
class MyDerivedClass : public MyBaseClass {
virtual void setValue(int);
// explicit: keep original behavior for SpecialType
virtual void setValue( SpecialType* p ) { MyBaseClass::setValue(p); }
};

Safely override C++ virtual functions

I have a base class with a virtual function and I want to override that function in a derived class. Is there some way to make the compiler check if the function I declared in the derived class actually overrides a function in the base class? I would like to add some macro or something that ensures that I didn't accidentally declare a new function, instead of overriding the old one.
Take this example:
class parent {
public:
virtual void handle_event(int something) const {
// boring default code
}
};
class child : public parent {
public:
virtual void handle_event(int something) {
// new exciting code
}
};
int main() {
parent *p = new child();
p->handle_event(1);
}
Here parent::handle_event() is called instead of child::handle_event(), because the child's method misses the const declaration and therefore declares a new method. This could also be a typo in the function name or some minor difference in the parameters types. It can also easily happen if the interface of the base class changes and somewhere some derived class wasn't updated to reflect the change.
Is there some way to avoid this problem, can I somehow tell the compiler or some other tool to check this for me? Any helpful compiler flags (preferably for g++)? How do you avoid these problems?
Since g++ 4.7 it does understand the new C++11 override keyword:
class child : public parent {
public:
// force handle_event to override a existing function in parent
// error out if the function with the correct signature does not exist
void handle_event(int something) override;
};
Something like C#'s override keyword is not part of C++.
In gcc, -Woverloaded-virtual warns against hiding a base class virtual function with a function of the same name but a sufficiently different signature that it doesn't override it. It won't, though, protect you against failing to override a function due to mis-spelling the function name itself.
As far as I know, can't you just make it abstract?
class parent {
public:
virtual void handle_event(int something) const = 0 {
// boring default code
}
};
I thought I read on www.parashift.com that you can actually implement an abstract method. Which makes sense to me personally, the only thing it does is force subclasses to implement it, no one said anything about it not being allowed to have an implementation itself.
In MSVC, you can use the CLR override keyword even if you're not compiling for CLR.
In g++, there's no direct way of enforcing that in all cases; other people have given good answers on how to catch signature differences using -Woverloaded-virtual. In a future version, someone might add syntax like __attribute__ ((override)) or the equivalent using the C++0x syntax.
In MSVC++ you can use keyword override
class child : public parent {
public:
virtual void handle_event(int something) <b>override</b> {
// new exciting code
}
};
override works both for native and CLR code in MSVC++.
Make the function abstract, so that derived classes have no other choice than to override it.
#Ray Your code is invalid.
class parent {
public:
virtual void handle_event(int something) const = 0 {
// boring default code
}
};
Abstract functions cannot have bodies defined inline. It must be modified to become
class parent {
public:
virtual void handle_event(int something) const = 0;
};
void parent::handle_event( int something ) { /* do w/e you want here. */ }
I would suggest a slight change in your logic. It may or may not work, depending on what you need to accomplish.
handle_event() can still do the "boring default code" but instead of being virtual, at the point where you want it to do the "new exciting code" have the base class call an abstract method (i.e. must-be-overridden) method that will be supplied by your descendant class.
EDIT: And if you later decide that some of your descendant classes do not need to provide "new exciting code" then you can change the abstract to virtual and supply an empty base class implementation of that "inserted" functionality.
Your compiler may have a warning that it can generate if a base class function becomes hidden. If it does, enable it. That will catch const clashes and differences in parameter lists. Unfortunately this won't uncover a spelling error.
For example, this is warning C4263 in Microsoft Visual C++.
C++11 override keyword when used with the function declaration inside the derived class, it forces the compiler to check that the declared function is actually overriding some base class function. Otherwise, the compiler will throw an error.
Hence you can use override specifier to ensure dynamic polymorphism (function overriding).
class derived: public base{
public:
virtual void func_name(int var_name) override {
// statement
}
};
class MyClass {
public:
MyClass() {}
virtual uint32_t someFunction(bool param = false) {
if (param) {
std::cout << "This is an example virtual function with default code" << std::endl;
}
return 1100; //just for return something
};
then you can override the function as you need
class MyClass2 : public MyClass {
public:
MyClass2();
uint32_t someFunction(bool param) override;
};
uint32_t MyClass2::someFunction(bool verbose) {
std::cout << "This is new implementation for virtual method " << std::endl;
}

connect pure-virtual SIGNAL of an abstract class to a SLOT from constructor [duplicate]

I am making an abstract-base-class and was thinking I might want a pure virtual signal. But when I compiled I get a warning for the pure virtual signals I have defined:
../FILE1.h:27: Warning: Signals cannot be declared virtual
../FILE1.h:28: Warning: Signals cannot be declared virtual
Is it valid to define a pure virtual signal in C++/Qt? Is it valid to define a virtual signal?
Qt's signal and slot documentation page says you can define virtual slots but doesn't talk about signals. I can't seem to find good information on pure virtual signals.
Signals don't ever have an implementation[1] (i.e. you define the signal in your .h file and then there is no implementation in the .cpp).
The main purpose of declaring a function pure virtual is to force the inheriting class to provide an implementation.
Given the above two statements here's my thinking:
Signals don't have an implementation but declaring it pure virtual will require the inheriting class to provide an implementation... which directly conflict with "signals don't have an implementation". It's like asking someone to be in two places at once it's just not possible.
So in conclusion it seems like declaring a "pure virtual" "signal" should be an error and thus not valid.
In the case of an abstract base class here's what I think is correct:
When one declares the function only "virtual" it still gives the warning. To avoid any warnings I think the solution is to not qualify the signal with any "virtual" or "pure virtual" and then the inheriting class will not declare any signals but can still emit the signals defined in the base class.
[1] when I say that "signals don't ever have an implementation" I mean that the person implementing the class doesn't provide the implementation. I understand that behind the scene Qt's moc provides an implementation in the moc_FILE1.cpp .
The warning is reported by moc, not by the C++ compiler, and it is valid except in the specific case of abstract interfaces.
The only valid use for virtual signals is when declaring abstract interfaces that don't derive from QObject, as detailed in this excellent answer. There's nothing wrong with that approach. Moc tries to be helpful, since in most cases a virtual signal is a mistake.
Even then, the simple workaround for not getting the warning is to skip the signals: keyword in the interface. It is completely unnecessary, since the interface doesn't derive from QObject and thus shouldn't be processed by moc at all:
// https://github.com/KubaO/stackoverflown/tree/master/questions/virtual-slot-10029130
#include <QtCore>
class IDogInterface {
public:
// no signals: section since it's not a QObject!
virtual void barks() = 0; // a signal
};
class ADog : public QObject, public IDogInterface {
Q_OBJECT
public:
Q_SIGNAL void barks() override; // implementation is generated by moc
};
class Monitor : public QObject {
Q_OBJECT
int m_count{};
Q_SLOT void onBark() { m_count++; }
public:
int count() const { return m_count; }
void monitorBarks(IDogInterface * dog) {
QObject * dogObject = dynamic_cast<QObject*>(dog);
if (dogObject) {
connect(dogObject, SIGNAL(barks()), SLOT(onBark()));
} else {
qWarning() << "cannot monitor barking on dog instance" << (void*)dog;
}
}
};
int main() {
ADog dog;
Monitor monitor;
monitor.monitorBarks(&dog);
emit dog.barks();
Q_ASSERT(monitor.count() == 1);
}
#include "main.moc"
I think there's simply no point in having (pure) virtual signals. the signals macro provided to Qt simply expands to protected, so all the signals you're declaring are actually declarations of protected methods. The code generated by moc will provide the implementations of those functions.
there is a solution to create pure virtual function which will connect given slot to signal or vice versa. e.g.:
class IBaseInterface
{
public:
virtual bool connectToSignal1(QObject* pReceiver, const char* pszSlot, bool bConnect) const = 0;
};
class CDerived : public QObject, public IBaseInterface
{
Q_OBJECT
public:
virtual bool connectToSignal1(QObject* pReceiver, const char* pszSlot, bool bConnect) const;
signals:
void signal1(const QString& msg);
};
bool CDerived::connectToSignal1(QObject* pReceiver, const char* pszSlot, bool bConnect) const
{
if(bConnect)
return connect(this, SIGNAL(signal1(QString)), pReciever, pszSlot);
return disconnect(this, SIGNAL(signal1(QString)), pReciever, pszSlot);
}
further in clients code one may type:
class CSomeClass : public QObject
{
Q_OBJECT
protected /*or public, or private*/ slots:
void someSlot(const QString& msg);
};
void CSomeClass::somefunction()
{
IBaseInterface* p = new CDerived;
if (!p->connectToSignal1(this, SLOT(someSlot(QString)), true))
QMessageBox::warning(this, tr("Warning"), tr("Cannot connect ...."), QMessageBox::Ok);
}
Two scenarios where a virtual signal makes sense:
The derived class may want to selectively block the sending of a signal by skipping the base class implementation.
The derived class may want to use it as an event mechanism and react to the signal before or after sending it to listeners.
Both scenarios can also be handled in other less-OOP ways.