Cannot subclass QObject
-
I have problems with connect() still, I have spent many days trying to resolves these issues and I still don't get it.
I have a class defined like this
@
#include <QtCore/QObject>
...
class HydrogenSwing : public QObject, public Groove
{
Q_OBJECT
public:
HydrogenSwing(QObject *parent=0 );@Constructor in the .cpp file like this
@HydrogenSwing::HydrogenSwing(QObject * _parent) :
QObject( _parent ),
Groove()void HydrogenSwing::init()
{
song * s = engine::getSong();
connect( s, SIGNAL(projectLoaded()), this, SLOT(update()) ); <- this fails @....
plus the moc at the bottom@#include "moc_HydrogenSwing.cxx"@
It seems to be saying my class is not a subclass of QObject, In QtCreator QObject is not purple like other classes and this is the output when I build.
/home/teknopaul/c++_workspace/lmms-0.4.13/src/core/HydrogenSwing.cpp: In member function ‘void HydrogenSwing::init()’:
/home/teknopaul/c++_workspace/lmms-0.4.13/src/core/HydrogenSwing.cpp:33:271: error: no matching function for call to ‘HydrogenSwing::connect(song*&, const char*, QObject*, const char*)’
/home/teknopaul/c++_workspace/lmms-0.4.13/src/core/HydrogenSwing.cpp:33:271: note: candidates are:
/opt/QtSDK/Desktop/Qt/4.8.0/gcc/include/QtCore/qobject.h:204:17: note: static bool QObject::connect(const QObject*, const char*, const QObject*, const char*, Qt::ConnectionType)
/opt/QtSDK/Desktop/Qt/4.8.0/gcc/include/QtCore/qobject.h:204:17:* note: no known conversion for argument 1 from ‘song*’ to ‘const QObject*’*
/opt/QtSDK/Desktop/Qt/4.8.0/gcc/include/QtCore/qobject.h:217:17: note: static bool QObject::connect(const QObject*, const QMetaMethod&, const QObject*, const QMetaMethod&, Qt::ConnectionType)
/opt/QtSDK/Desktop/Qt/4.8.0/gcc/include/QtCore/qobject.h:217:17: note: no known conversion for argument 1 from ‘song*’ to ‘const QObject*’
/opt/QtSDK/Desktop/Qt/4.8.0/gcc/include/QtCore/qobject.h:337:13: note: bool QObject::connect(const QObject*, const char*, const char*, Qt::ConnectionType) const
/opt/QtSDK/Desktop/Qt/4.8.0/gcc/include/QtCore/qobject.h:337:13: note: no known conversion for argument 1 from ‘song*’ to ‘const QObject*’#include <QtCore/QObject> has the tool tip "no such file or directory."
If i cast everything to QObject it compiles
@QObject::connect( (QObject*)s, SIGNAL(lengthChanged()), (QObject*)this, SLOT(frameChange()) );@
But no other code in the same project is doing that.
In fact I can go and get a line of connect() code from any other class in the project, copy it into my class and it will no longer compile.
@ connect( engine::mainWindow(), SIGNAL( periodicUpdate() ),
this, SLOT( update() ) );@works in one class but not in my class.
update() is defined as a slot like this
@public slots:
// valid values are from 0 - 127
void setAmount(int _amount);
void update();@and a moc_*.cxx file IS being generated with every build and compile. using QT_WRAP and friends.
I'm guessing some how this class compiles as the subclass of some other QObject with out the connect magic.
I've tried with single hierarchies as well without it working.
I've read the docs through and through and I have 3 classes with signals ans slots working fine but this one just will not work and I'm totally lost. It seems fine to me, I cant see any difference with this class and others.
-
song is a sub class of QObject eventually, not direct.
HydrogenSwing.cpp has a header HydrogenSwing.h which is where the first code snippet comes from .
This is compiled with moc and cmake, it compiles, currently the connect() lines are commented out and the code compiles and runs.
Its only signals and slots that I can not get to work. I can call slot methods directly without problems. -
Î assume that song is no QObject subclass.
bq. no known conversion for argument 1 from ‘song*’ to ‘const QObject*’
aditionally, why do you include the moc file explicitly? If the class definition is in the header file and you use qmake, the moc file should automatically be included inside the build.
-
When the compiler is dealing with HydrogenSwing and the offending connect() it does not know that song is a QObject derivative becuase the necessary information is not present. The compiler is telling you this. Clearly your cpp file does not include a declaration of the class song that would enable to compiler to know this. This has nothing to do with the pedigree of HydrogenSwing.
The solution is as simple as:
#include "song.h"or something similar
-
OK that fixed it, thanks, added the include to the HydrogenSwing.cpp file.
I didn't understand how song * s = engine::getSong(); compiles without it.
Forgive my noobness I come from a Java background.
error: no matching function for call to ‘HydrogenSwing::connect(song*&, const char*, QObject*, const char*)’
tells you that song.h is missing but it tells me a lot less. :)
I assumed song "is a" QObject.
In Java the compiler knows nothing about a class and complains about that before complaining about a object hierarchy. So I assumed that if the compiler can compile song, it has access to song.h, I guess that's not the case. When I type "make" song compiles too, so I presume that there must be different instances of the compiler with different sets of references at different points during the build?It seems make can compile references to a class song without the song include somewhere in the long chain of includes, I don't really understand how it does that. I guess it just has a string "song" in some intermediary file and lets the linker worry about it?
I assume and include that has an include imports everything in both files right? Or is there any difference to have an #include in a particular .cpp file compared to its header file?
Most of the Class files in this project have about 10% of the includes compared to the number of classes they appear to reference.
Would it not be possible to have a header file called all.h that contains
cat include/*.h > all.h
Then everything would just need one import statement? Or am I missing something?
:P
-
What the compiler did know, is
that s is a pointer to an object of type song
that method engine::getSong() returns a pointer of type song
This is enough to decide that the type of the returned object is compatible to the type of s - which is easy, as both are the same :-)
What the compiler does not know, is of which class hierarchy a song is made of. So, in turn, the compiler does not know, that somewhere up in the hierarchy, song inherits from QObject. It does know that only if you include the header file song.h.
If you just hard cast (C style cast) the s pointer to a QObject pointer - using (QObject *)s - everything is ok for the compiler, but you run into the possible problem that s is not of type QObject and the your program will crash at runtime.
As a side note: Please always avoid C style casts - (Type *)othertype -, but use static_cast<>(), dynamic_cast<>(), const_cast<>(), or, in case of QObject based classes, qobject_cast<>(). It's good practice to check the cast result afterwards unless your absolutely sure that it succeeds. This avoids using a probably null pointer.
-
Included files are recursively processed and may themselves drag in other declarations.
You can forward declare a class, which is sufficient to allow declaring a pointer to the class but not sufficient to access the class members from the implementation. My guess is that some header you were including contains something like:
@
class song; // a forward declarationclass Foo {
...
private:
song *m_song; // that allows this
};
@in order to declare a pointer to song. The compiler knows song exists, and can create pointer to one, but does not know anything of song's implementation including inheritance.