Qt c++ class+subclass using Q_OBJECT doesn´t work - c++

I`m having the hardest time in creating a class+subclass using Q_OBJECT:
I have a class geometry and some classes Geo_1PF, Geo_2,.. that inherit from geometry. I created those classes an everything worked well. Now I want to use QMetaType and for that I need to declare Q_Object.
Once I used Q_OBJECT / Q_DECLARE_METATYPE my problems started.
I get the error "undefined reference to vtable for ..."
I tried to delete all .o and all moc_.cpp before compiling again. I added QT += core in the *.pro-File but I didn`t succeed.
Do I have to put Q_OBJECT / Q_DECLARE_METATYPE in both the parent and the cild class?
Why do I get that error ?
Can somebody help me please?
This is my code:
geometry.h:
#ifndef GEOMETRY_H
#define GEOMETRY_H
#include <QMetaType>
#include <QWidget>
#include <QObject>
#include <QDebug>
class Geometry
{
// Q_OBJECT
protected:
public:
Geometry();
virtual ~Geometry(void) {}
virtual void write_LNE();
//Q_DECLARE_METATYPE(Geometry);
#endif // GEOMETRY_H
-
geometry.cpp:
#include "geometry.h"
Geometry::Geometry()
{ qDebug() << "Constructor: hier ist Geometry"; }
void Geometry::Haupt()
{ qDebug() << " Das hier ist die Haupt von Geometry ....." ; }
void Geometry::write_LNE(){}
-
Geo_1PF.h:
#ifndef GEO_1PF_H
#define GEO_1PF_H
#include "geometry.h"
class Geo_1PF : public Geometry
{
// Q_OBJECT
public:
Geo_1PF();
~Geo_1PF() {}
virtual void write_LNE();
};
//Q_DECLARE_METATYPE(Geo_1PF);
#endif // GEO_1PF_H
Geo_1PF.cpp:
#include "Geo_1PF.h"
Geo_1PF::Geo_1PF()
{
}

If you want to use Q_OBJECT your class should inherites from QObject or its subclasses
class Geometry : public QObject
{
Q_OBJECT
//...
See Using the Meta-Object Compiler (moc)

First, the Q_OBJECT macro is not inheritable. It must be included in every object that directly or indirectly inherits QObject. If your base class is QObject derived, then your derived class is also QObject derived, and thus must include the macro.
From the documentation:
The Q_OBJECT macro must appear in the private section of a class
definition that declares its own signals and slots or that uses other
services provided by Qt's meta-object system.
Second, Q_DECLARE_METATYPE() requires that the object has a copy constructor, and QObject doesn't support copy constructors by design, so it is impossible to use Q_DECLARE_METATYPE() with a QObject derived class. And it doesn't make sense either, because every QObject is automatically a meta type, since it is being processed by the meta object compiler. It will work if you declare a pointer to your type - Q_DECLARE_METATYPE(Geometry*). Registering a type as a meta type requires the type to have a copy constructor, if it doesn't you get an error.
From the looks of your classes, they don't need to derive from QObject, so you should not do that, you should remove the macro (and never use it if you are not inheriting a QObject or derived), and then Q_DECLARE_METATYPE(Geometry) should work. It looks like you were under the impression you need Q_OBJECT to Q_DECLARE_METATYPE() but in reality it is the opposite - the two are incompatible - the latter must have and the former must not have a copy constructor.

Related

What are all the requirements of a QObject derived class?

I'm working on my first non-trivial project using the Qt Framework and to help maintain consistency across documents and to ensure I don't forget some small requirement I've decided to make a template document demonstrating the member functions, macros, etc. needed to subclass QObject. I also want to be able to fully utilize the Meta Object system. Am I missing anything or misunderstanding anything? Also feel free to give any general C++ critiques as necessary.
I'm especially concerned with the issue of whether or not to include a copy constructor. Is that only necessary for classes not derived from QObject?
Requirements (links are to the document I got the requirements from)
Public Default Constructor (link)
Public Copy Constructor (see 1) (but conflicts with this)
Public Destructor (see 1)
Use the Q_OBJECT Macro (link)
Ensure Properties Are Accessible with the Q_PROPERTY(...) Macro (link)
Declare the Type with Q_DECLARE_METATYPE(T) in the Header (link) (link)
Declare any Enums Used with Q_ENUM(E) in the Header (link)
Template Header
// Include guards
#ifndef CLASSNAME_H
#define CLASSNAME_H
// Include statements
#include <QObject>
#include <T.h>
// Enum definition
enum E{
E0,
E1,
E2
};
// Q_ENUM Macro
Q_ENUM(E)
// Class declaration
class ClassName : public QObject
{
// Q_OBJECT Macro
Q_OBJECT
// Q_PROPERTY Macros
Q_PROPERTY(T* memberA READ memberA WRITE setMemberA NOTIFY memberAChanged)
Q_PROPERTY(int memberB READ memberB WRITE setMemberB NOTIFY memberBChanged)
Q_PROPERTY(E memberC READ memberC WRITE setMemberC RESET resetMemberC)
public:
// Constructors and Destructor
ClassName(QObject *parent = nullptr);
ClassName() = default;
ClassName(const ClassName&) = default;
~ClassName();
// Getters
T* memberA() const {return m_memberA;}
int memberB() const {return m_memberB;}
E memberC() const {return m_memberC;}
// Setters
void setMemberA(T* newA);
void setMemberB(int newB);
void setMemberC(E newC);
signals:
void memberAChanged(T*);
void memberBChanged(int);
public slots:
void resetMemberC();
private slots:
private:
// Data Members
T* m_memberA;
int m_memberB;
E m_memberC;
};
// Meta Object Type Declaration
Q_DECLARE_METATYPE(TypeName);
// End include guard
#endif // CLASSNAME_H
The source file to accompany this header would likely be trivial, so I won't include it here. Though if anyone thinks it would be helpful to demonstrate some requirement or functionality, I'd be happy to write it out.
As Jeremy Friesner suggested, the requirements are not that strict. The situation is more like this:
If your class uses signals and/or slots, it must both have the Q_OBJECT macro and be derived from QObject,
If it only uses other meta-object functionality, such as Q_PROPERTY declarations, it can use the Q_GADGET macro and need not be derived from QObject,
If it doesn't need any of that, but should still be compatible with Qt templates like QVariant, it should be declared with Q_DECLARE_METATYPE. The same applies to enums and Q_ENUM.
A Q_PROPERTY/Q_INVOKABLE interface is only really needed if you need your class to be interoperable with QML code.
As for your other question, yes that is an important difference between QObjects and non-QObjects. The metatype must be copyable, which is why that is required of types you manually declare as metatypes, and also why the system instead uses pointers for QObject types, which are not copyable themselves. A minimal QObject declaration could start like this:
#ifndef CLASSNAME_H
#define CLASSNAME_H
#include <QObject>
// Enums in the global namespace cannot be registered; they must be enclosed
// in a class and registered with Q_ENUM, or in a namespace declared as
// Q_NAMESPACE and registered with Q_ENUM_NS
class ClassName : public QObject
{
Q_OBJECT
public:
// Default constructor, with explicit specifier to prevent accidental
// implicit conversion from a QObject*
explicit ClassName(QObject *parent = nullptr);
};
// ClassName* is automatically declared as a metatype
#endif // CLASSNAME_H
In general I'd recommend the "rule of zero": if possible, do not declare a destructor, nor any copy and move operations, and leave them to the compiler. Of course I also recommend all of the other guidelines there, if you have the time!

How to enforce Q_OBJECT macro usage for classes with signals and slots

I have a bunch of base classes with defined Q_OBJECT macro and derived classes without it:
class Base : public QObject
{
Q_OBJECT
public:
// signals and slots
};
class Derived : public Base
{
// notice no `Q_OBJECT` macro
public:
// signals and slots
};
That works fine, but according to Qt docs:
The Q_OBJECT macro must appear in the private section of a class
definition that declares its own signals and slots or that uses other
services provided by Qt's meta-object system.
Is there any way to stop compilation when Q_OBJECT macro is absent for classes which use Qt meta-system?
PS: I'm using MSVC compiler

Pimpl idiom with Qt

I am trying to build a shared library with Qt 5.6.0 and i would like to use Pimpl.
I have one class to export and this class inherits from QGraphicsScene, which itself inherits from QObject :
// CustomScene.h
#include "customscene_global.h" // recommended header from Qt
#include <QGraphicsScene> // do not compile if not present
// forward declarations
class CustomSceneImpl;
template <typename T> class QList;
class QString;
template <class Key, class T> class QMap;
// some other classes ...
class CustomScene : public QGraphicsScene
{
Q_OBJECT
public :
// some public functions
signals:
// some custom signals
public slots:
// some custom public slots
private:
CustomSceneImpl *m_pimpl; // pointer to private members
};
Everything's is fine if i #include <QGraphicsScene> in this header but i would prefer to forward declare QGraphicsScene. However i get the following compile error if i do that :
error: invalid use of incomplete type 'struct QGraphicsScene'
I guess i am doing something wrong with the QObject Macro, that is not recognized, and with the moc in general.
I know there are dedicated Qt Macro to use Pimpl ( Q_D, .. ) but i did not really understand how to use them and if it would fix this issue.
Thanks for your help.
Everything's is fine if i #include QGraphicsScene in this header but i would prefer to forward declare QGraphicsScene.
you cannot do it as you inherit from QGraphicsScene:
class CustomScene : public QGraphicsScene
btw. this error has nothing to do with the way you implemented PIMPL idiom (actually it looks fine), inheritance from incomplete type is simply not possible as compiler needs to know the size / layout of your base class.
Since a forward declared class has no information about the content, you can't use it for inheritance.
You can use PIMPL idiom for composition, not for inheritance. If you need to inherit from QGraphicsScene, you cannot forward declare it. You have to include its full definition.

What's the purpose of Q_INTERFACES macro?

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.

Getting the name of sub class within super class in Qt

I have a base class that is inherited by two sub classes. All three classes use qDebug() to do some debug printing and Q_FUNC_INFO to identify the source of the print. The problem is that when printing from the base class, Q_FUNC_INFO contains the name of the base class, making it impossible to know which of the two sub classes the instance represents.
The best solution I have come up with so far is using a QString variable instead of Q_FUNC_INFO at the base class and supplying it with the correct name when instantiating.
Are there any other, more preferable solutions?
Are there any other, more preferable solutions?
In general, no, that is fine. In such cases, you would need to place the Q_FUNC_INFO into the subclass if that is possible. If not, you are out of luck, but... please read on.
Qt internally also uses explicit strings rather than Q_FUNC_INFO, I believe partially for this reason.
For QObjects, you could use the meta object compiler for some introspection to get the real name dynamically, namely:
const char * QMetaObject::className() const
Returns the class name.
and
const QMetaObject * QObject::metaObject() const [virtual]
Returns a pointer to the meta-object of this object.
A meta-object contains information about a class that inherits QObject, e.g. class name, superclass name, properties, signals and slots. Every QObject subclass that contains the Q_OBJECT macro will have a meta-object.
The meta-object information is required by the signal/slot connection mechanism and the property system. The inherits() function also makes use of the meta-object.
If you have no pointer to an actual object instance but still want to access the meta-object of a class, you can use staticMetaObject.
You also take a look into this when dealing with constructors as your comment seems to indicate it:
QMetaMethod QMetaObject::constructor(int index) const
Returns the meta-data for the constructor with the given index.
main.cpp
#include <QObject>
#include <QDebug>
class Foo : public QObject
{
Q_OBJECT
public:
virtual void baz() { qDebug() << "Class name:" << metaObject()->className(); }
};
class Bar : public Foo
{
Q_OBJECT
};
#include "main.moc"
int main()
{
Bar bar;
bar.baz();
return 0;
}
Output
moc main.cpp -o main.moc && g++ -Wall -I/usr/include/qt -I/usr/include/ -I/usr/include/qt/QtCore -lQt5Core -fPIC main.cpp && ./a.out
Class name: Bar
Note: if you would like to get this mechanism work in the constructor, the simple answer is that you cannot. Nothing will really help you there. That is due to the fact how inheritance is handled in C++. First, the base class is constructed, and at that stage, the subclass is yet fully constructed (strictly speaking, not even the base), so you cannot really get more information about it without explicitly making sure with an additional argument to the base class constructor. But then, you would get a bloated API just for this simple thing. I would suggest in such a case to just put the print into the subclasses as opposed to the base classes.