Determining super class for registered user types - qt

I am attempting to determine which classes are subclassed from several different types. For example, if E1 extends A, E2 extends A, and E3 extends B, I want to find all classes that are subclassed from A and return a list of the types E1 and E2. These types are registered with the QMetaSystem.
My first attempt was to iterate over the user declared types, instantiate it, and get the superClass name:
int type = QMetaType::User;
while( QMetaType::isRegistered(type) ) {
QObject *o = (QObject*)QMetaType::construct(type);
QString parent = o->metaObject()->superClass()->className();
}
This seemed like a bad idea when I wrote it and didn't expect it to work. Unsurprisingly, it segfaults when attempting to get the metaObject.
Is it possible to get the information I need from the QMetaType or is there another way of getting this information?
Update
The problem seems to be in trying to iterate over all the user types. Before I register my types, some Qt type seem to be getting registered before mine. Specifically, the two registered types are QPaintBufferCacheEntry (typeId = 256) and QPaintBufferCacheEntryV2 (typeId = 257). I can initialize the object just fine, but it crashes when I attempt to get the meta object, so I'm thinking the cast is illegal. I'm not quite sure where these are being registered because my code base is not doing it explicitly.
I took this to mean that it just wasn't safe to iterate over and construct each of the user types.

Your idea is correct. This should give you the name of the parent class:
QObject *o = (QObject*)QMetaType::construct(type);
QString parent = o->metaObject()->superClass()->className();
For it to work, your classes must have been declared with Q_DECLARE_METATYPE(Type) and registered with qRegisterMetaType(). This is the case as QMetaType::isRegistered(type) is true.
Your user defined classes must also inherits from QObject (directly or not) and have the Q_OBJECT macro in their definition. This could explain your segfault.
superClass() can also return 0 if there is no parent class, but here all your classes should at least inherit QObject.
There is also QObject::inherits(const char * className) to know if an object is of a class inheriting, even indirectly, from className.

Related

Dart - Casting List<SuperType> to List<SubType> using generics

I am new to Flutter and Dart, coming from native Android.
Android has a very nice database abstraction architecture called the Room Persistence Library. As far as I am aware, no such database abstraction architecture exists for Flutter using the MVVM / MVC design patterns.
My solution was to create a Dart version of it myself. I got it pretty much done after a few headaches, but I cannot seem to get LiveData to work properly using generics.
I set up my class like this:
class LiveData<T> {
...
}
Now when I want to return some data, it can either be an Object or List<Object>. I found a neat hack for differentiating the two from T:
...
// Parse response
// This checks if the type is an instance of a single entity or a list.
if (entity is T) {
cachedData = rawData.isEmpty ? null : entity.fromMap(rawData.first) as T;
} else {
cachedData = rawData.map((e) => entity.fromMap(e)).toList() as T;
}
...
The problem lies in the second block:
cachedData = rawData.map((e) => entity.fromMap(e)).toList() as T;
With the error:
- Unhandled Exception: type 'List<Entity>' is not a subtype of type 'List<Vehicle>' in type cast
The question then becomes: How can I cast Entity to Vehicle when I do not have access to the Vehicle class. Only an instance of it is assigned to an Entity entity variable.
Here's a snippet to demonstrate my access to Vehicle:
final Entity entity;
...assign Vehicle instance to entity...
print(entity is Vehicle) // True
I've tried using .runtimeType to no avail. I have also thought about splitting LiveData into two classes, the second one being LiveDataList. Although this seems to be the easiest solution to not bug the code- it would bug me (bad pun is intentional) and break the otherwise pretty direct port of Room.
As a temporary solution, I have abstracted out the build logic into a generic function to be passed to the LiveData in the constructor.
final T Function(List<Map<String, dynamic>> rawData) builder;
And now I call that instead of the previous code to build the cachedData.
// Parse response
cachedData = builder(rawData);
With the constructor for the LiveData<List<Vehicle>> called when accessing all vehicles in the Dao<Vehicle> being:
class VehicleDao implements Dao<Vehicle> {
...
static LiveData<List<Vehicle>> get() {
return LiveData<List<Vehicle>>(
...
(rawData) => rawData.map((e) => Vehicle.fromMap(e)).toList(),
...
);
}
}
In Dart (and indeed in many languages) generics screws with the concept of inheritance. You would think that if Bar inherits from Foo, that List<Bar> would also be castable to List<Foo>.
This is not actually going to be the case because of how generics work. When you have a generic class, every time you use that class with a different type, that type is treated as a completely separate class. This is because when the compiler compiles those types, class MyGenericType<Foo> extends BaseClass and class MyGenericType<Bar> extends BaseClass are basically converted to something like class MyGenericType_Foo extends BaseClass and class MyGenericType_Bar extends BaseClass.
Do you see the problem? MyGenericType_Foo and MyGenericType_Bar are not descendants of one another. They are siblings of each other, both extending from BaseClass. This is why when you try to convert a List<Entity> to List<Vehicle>, the cast doesn't work because they are sibling types, not a supertype and subtype.
With all this being said, while you cannot directly cast one generic type to another based on the relationship of the generic type parameter, in the case of List there is a way to convert one List type to another: the cast method.
List<Entity> entityList = <Entity>[...];
List<Vehicle> vehicleList = entityList.cast<Vehicle>(); // This cast will work
One thing to note though, if you are casting from a supertype generic to a sub-type generic and not all the elements of the list are that new type, this cast will throw an error.

Unable to pass reference of GLWidget class in Qt

I have a class called MainWindow and it initializes objects of GLWidget and clothWidget class, both aforementioned classes inherit QGLWidget class. Initialization in MainWindow class is like
glWidget = new GLWidget();
clWidgetf = new clothWidget();
and I have an object of GLWidget class declared in clothwidget.h. When I do
clwidgetf->gl = glwidget ( here gl is object of class GLWidget declared in ClothWidget class) in MainWindow
I get following errors
/usr/include/qt4/QtOpenGL/qgl.h:592: error: 'QGLWidget&
QGLWidget::operator=(const QGLWidget&)' is private
/home/arun/Desktop/garment/glwidget.h:8: error: within this context
The problem is you are (unintentionally) trying to copy the widget, and since it is QObject based it cannot be copied. In the "olden days" (until very recently) the only way to make that was to make the copy constructor private, which is exactly the error message you are getting. Double-check your code to make sure you are not passing as a value copy (as Riateche suggested in the comments).
If you want a reference then you have to initialize it with your object, you can not set it elsewhere, but most likely you want a pointer so you should pass pointer to your function and make your class member a pointer too, or take an adress of passet reference and still assign it to some pointer.
And you can't copy anything derived from QObject since constructors are private.

Why the "q_ptr" pointer is assigned to "this" pointer of QObject?

Like the title,why the "q_ptr" pointer is assigned to "this" pointer of QObject? in source code.
QObject::QObject(QObjectPrivate &dd, QObject *parent)
: d_ptr(&dd)
{
>>Q_D(QObject);
>>d_ptr->q_ptr = this;/*question*/
.......
Then,when use Q_Q() macro in source code like blow:
Q_Q(QWidget)
It will return the q pointer handled by the function q_fun():
QWidget*q_func() {return static_cast<QWidget*>(q_ptr);}
As all we know,static_castis not safe when cast from parent to child.
I am very frustrated about /*question*/ ,can any guy tell me the secret?Thanks!
d_ptr->q_ptr = this;/*question*/
This is where the private implementation object (PIMPL idiom) is told about the object it is working for/with (the non-private QObject). Here's a good link for info about Qt and d pointers (d_ptr).
Q_Q macro returns the pointer to the QObject, so you can emit signals from it (among other things). As for the static_cast bit, that is safe because the macro is defined differently for each class created by the Q_DECLARE_PRIVATE and Q_DECLARE_PUBLIC macros: the result being, static_cast is always casting to the correct type. Again, I recommend reading the link.

Convert a QStandardItemModel to a QVariant

I'm trying to send a QStandardItemModel-derived object to PythonQt, but I'm a little confused on how it needs to be sent. When I was using boost::python I had several controls like boost::noncopyable to ensure I wasn't recreating this object, but sharing it with python. I also had constructs to provide a boost shared pointer to python from inside python.
class Scene : public boost::enable_shared_from_this<Scene>, public QStandardItemModel
In PythonQt, however, I'm not sure what's available. The function call takes a QVariantList for all the function parameters.
QVariant PythonQt::call(PyObject* object, const QString &callable, const QVariantList &args = QVariantList))
What I'm confused about now is how to get my object to python via a QVariant. Since its derived from QStandardItemModel, I figured it would already be register
void MyObject::someFunction(QString fileName)
{
QVariant myObjectV = qVariantFromValue(this);
// send to python
...
}
But this gives me the following error:
'qt_metatype_id' : is not a member of 'QMetaTypeId<MyObject>'
I've tried registering it after I declare my class, but this throws a different error.
class MyObject : public QStandardItemModel
{
Q_OBJECT
...
};
Q_DECLARE_METATYPE(MyObject)
QStandardItemModel::QStandardItemModel(const QStandardItemModel&) is private within this context.
I actually get the error twice--once in header where I add the Q_DECLARE_METATYPE and in another header, which has a class which always derives from QStandardItemModel but is otherwise unrelated.
Is Q_DECLARE_METATYPE even the correct way to go about converting this object to a QVariant?
BOOST_PYTHON_MODULE(scene)
{
class_("Scene");
}
Yes, by default, QVariant can take one of te following types - http://doc.qt.io/qt-4.8/qvariant.html#Type-enum - and they are not enough for your task. You should declare additional types by yourself via qmetatype system. Thus you shoud call qRegisterMetaType() function.

QT: trouble with qobject_cast

I have derived QGraphicsItem and QGraphicsScene classes. I want the items to be able to call scene() and get a derviedGraphicsItem * instead of a QGraphicsItem *, so I reimplemented QGraphicsScene::itemAt to return a derived pointer.
DerivedItem* DerivedScene::itemAt( const QPointF &position, const QTransform &dt ) const
{
return qobject_cast< DerivedItem * >(
QGraphicsScene::itemAt(position, dt) );
}
I get the following error (Qt 4.6, GCC 4.4.3 on Ubuntut 10.4)
scene.cpp: In member function ‘DerivedItem* DerivedScene::itemAt(qreal, qreal, const QTransform&) const’:
scene.cpp:28: error: no matching function for call to ‘qobject_cast(QGraphicsItem*)’
I then noticed QGraphicsItem doesn't inherit QObject, so I made my derived QGraphicsItem class have multiple inheritance from QObject and QGraphicsItem, and after adding the Q_OBJECT macro and rebuilding the project I get the same error.
Am I going about this the wrong way? I know it's supposed to be bad design to try to cast a parent class as a child, but in this case it seems like what I want, since my derived item class has new functionality and its objects need a way to call that new functionality on items around themselves, and asking the items scene object with itemAt() seems like the best way - but I need itemAt() to return a pointer of the right type. I can get around this by having the derived items cast the QGraphicsItem * returned by QGraphicsScene::itemAt() using dynamic_cast, but I don't really understand why that works and not qobject_cast, or the benefits or disadvantages to using dynamic_cast vs. qobject_cast.
EDIT:
forgot to mention that I also reimplemented QGraphicsItem::scene() in my derived class to return a DerivedScene *, as
DerivedScene* DerivedItem::scene() const
{
return qobject_cast< DerivedScene * >( QGraphicsItem::scene() );
}
but this doesn't appear to be causing a compilation error...
There is no point in inheriting from QObject just for casting. The advantage of qobject_cast
over dynamic cast is summed up pretty much in the qobject_cast documentation:
The qobject_cast() function behaves similarly to the standard C++ dynamic_cast(), with the advantages that it doesn't require RTTI support and it works across dynamic library boundaries.
It's nice to have and useful if you have QObjects, but not worth to inherit from QObject if it is all you want from QObject.
Also, for QGraphicsIems there is qgraphicsitem_cast, which should do exactly what you want :)
You have to pass a QObject pointer to qobject_cast() and QGraphicsScene::itemAt returns a QGraphicsItem pointer. Since, as you mentioned, QGraphicsItem does not derive from QObject, the complier gave you that error.

Resources