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.
Related
I am reading other people's code and see this:
class UAVItem:public QObject,public QGraphicsItem
{
Q_OBJECT
Q_INTERFACES(QGraphicsItem)
...
But I didn't see they are using any sort of plug-in in this program.
Therefore, can I just remove the line:
Q_INTERFACES(QGraphicsItem)
?
If you have a class Derived which inherits from a class Base, which in turn inherits from QObject, and both Derived and Base contain the Q_OBJECT macro, then qobject_cast can be used to safely cast from a pointer (or reference) to Base, to a pointer (or reference) to Derived, similar to dynamic_cast in standard C++ but without RTTI.
If Base does not inherit from QObject, then qobject_cast can still be used in this way, but only if Base has a corresponding Q_DECLARE_INTERFACE macro and Derived contains Q_INTERFACES(Base).
In your case, Q_INTERFACES(QGraphicsItem) being present in UAVItem means that qobject_cast can be used to cast from a pointer (or reference) to QGraphicsItem to a pointer (or reference) to UAVItem, despite QGraphicsItem not inheriting from QObject.
From reference doc,
class ToolInterface
{
public:
virtual QString toolName() const = 0;
};
Q_DECLARE_INTERFACE(ToolInterface, "in.forwardbias.tool/1.0");
// Hammer in hammer.h (our Hammer plugin)
#include "toolinterface.h"
class Hammer : public QObject, public ToolInterface
{
Q_OBJECT
Q_INTERFACES(ToolInterface)
public:
QString toolName() const { return "hammer"; }
};
Q_EXPORT_PLUGIN2(hammer, Hammer);
When moc runs on the hammer.h code, it inspects Q_INTERFACES. It
generates code for a function called qt_metacall - void
*Hammer::qt_metacast(const char *iname). This goal of this 'casting' function is to return a pointer to an interface depending on iname.
moc also verifies whether the interface names that you have put inside
Q_INTERFACES have indeed been declared. It can do this by inspecting
the header files and looking for a Q_DECLARE_INTERFACE. In our case,
there is a Q_DECLARE_INTERFACE inside toolinterface.h.
According to http://qt-project.org/doc/qt-4.8/moc.html#multiple-inheritance-requires-qobject-to-be-first the QObject must be the first in the base classes when using multiple inheritance.
Is this because of some limitation in the moc tool or C++ memory layout problems are taken into consideration too, thus this restriction came into existence?
Assume that we have a class Test declared as:
class Test : public Foo, public QObject
{
Q_OBJECT
[..]
};
If you take a look at the moc_test.cpp file that the moc tool has generated, you will see something like:
[..]
const QMetaObject Command::staticMetaObject = {
{ &Foo::staticMetaObject, qt_meta_stringdata_Command,
qt_meta_data_Command, &staticMetaObjectExtraData }
};
[..]
Compiler will complain about staticMetaObject not being the member of Foo, as Foo is not a QObject. For some reason the moc tool generates this code taking the first parent class. Thus if you declare Test as:
class Test : public QObject, public Foo {};
The generated code will look fine to compiler.
I think this is made just for convenience because moc tool will hardly know which of the parent classes is a QObject without parsing the whole hierarchy.
Note: If you don't use the Q_OBJECT macro, you can derive your class from others in any order.
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.
i have a class that inherits from QObject and have the Q_OBJECT macro:
class SomeClass: public QObject
{
Q_OBJECT
public:
SomeClass(QObject *parent = 0);
void method1();
void method2();
...
};
in another class in the same header i create an instance of that class, and then i try to get all Methods from 'SomeClass' and store it in a QMap:
this->someclass = new SomeClass(); // in constructor.
...
cout<<"init some class methods"<<endl;
const QMetaObject *metaobj = dynamic_cast<QObject*>(this->someclass)->metaObject();
cout<<"offset "<<metaobj->methodOffset()<<endl;
for(int i = metaobj->methodOffset();i < metaobj->methodCount();i++){
QMetaMethod metamethod = metaobj->method(i);
//if(metamethod.methodType() == QMetaMethod::Method){
QString methodname = QString(metamethod.signature());
methodname = methodname.replace(QRegExp("\\(.*\\)"),"");
controlmethods.insert(methodname,metamethod);
cout<<"added method: "<<metamethod.signature()<<" as "<<methodname.toAscii().data()<<endl;
//}
}
But this do not showed me any method added because the methods offset is equals to the methods count, why can be? i dont get with the reason, Thanks any help.
You need to use the Q_INVOKABLE macro for each method you want to see in the QMetaObject.
From the documentation:
Q_INVOKABLE
Apply this macro to declarations of member functions to allow them to be invoked via the meta-object system. The macro is written before the return type, as shown in the following example:
class Window : public QWidget {
Q_OBJECT
public:
Window();
void normalMethod();
Q_INVOKABLE void invokableMethod(); };
The invokableMethod() function is marked up using Q_INVOKABLE, causing it to be registered with the meta-object system and enabling it to be invoked using QMetaObject::invokeMethod(). Since normalMethod() function is not registered in this way, it cannot be invoked using QMetaObject::invokeMethod().
You can also use the slots macro. I think Q_INVOKABLE may be more minimal, though.
QMetaObject is only aware of signals, slots, properties and other invokable member functions, occasionally referred to as "meta-methods" as a group.
Also, for the first line of your example, you should (probably) just call
const QMetaObject *metaobj = someClass->metaObject();
This isn't just cosmetic. The dynamic_cast would move type-checking to runtime, which isn't necessary if you know at compile time that someClass is a pointer to a QObject-derived class. (dynamic_casting to QObject* will work, and will get you the correct QMetaObject because of virtual inheritance, but it's unnecessary, less safe, and unclear.)
You don't actually need an instance of the class to get the meta-object:
const QMetaObject *metaobj = SomeClass::staticMetaObject();
This is possible because there is one QMetaObject per class, not per object.
For anyone who wants to know more about the meta-object system, I recommend coffee and the documentation. Usually you don't need to deal with QMetaObject instances directly, unless you're writing a scripting engine or something equally 'meta'. It's easy to unintentionally duplicate functionality Qt already provides.
Also, Q_DECLARE_METATYPE is not what you want.
There is some kind of ambiguity in the official docs.
First we see:
method() and methodCount() provide information about a class's
meta-methods (signals, slots and other invokable member functions).
But later:
int QMetaObject::methodCount() const Returns the number of methods in
this class, including the number of properties provided by each base
class. These include signals and slots as well as normal member
functions.
But actually we can't have access to 'normal' methods through Qt MetaObject System.
So, to get access to your methods, you should declare them with the Q_INVOKABLE macro:
Q_INVOKABLE void method1();
Q_INVOKABLE void method2();
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.