Perhaps the title looks somewhat unclear, so I’ll go straight to the example:

double d = 3.14; QVariant v(d); qDebug() << v.value<int>(); //3 

QVariant performed a cast of double -> int .

I want to do the same thing, but with pointers:

 class Foo : public QObject{ Q_OBJECT; }; Q_DECLARE_METATYPE(Foo*) static const int __idFoo = qRgisterMetaType<Foo*>("Foo*"); //... Foo *foo = new Foo(); QVariant v = QVariant::fromValue(foo); qDebug() << v.value<QObject*>(); //QObject(0x0) 

Type cast did not happen.
Question: Is it possible in some way to place a pointer to an object of a derived class in QVariant , but to extract a pointer to an object of a base class?

UPD: The code is almost the same as mine:

 class IRow : public QObject{ //... }; class FirstRow : public IRow{ //... }; class SecondRow : public IRow{ FirstRow *_first Q_PROPERTY(FirstRow* first READ first WRITE setFirst) public: FirstRow* first() const{ return _first; } void first(FirstRow *first){ _first = first; } //... }; 

Somewhere else there is a function that knows nothing about specific implementations of the IRow interface. It should read all available properties, of the object that came to it in the form of QVariant (otherwise, there is work with models), and bring the resulting value to the interface type ( IRow ). And here it is not given. In Qt5, it should, but in Qt4 - no way. If you use the @ixSci solution, then the SecondRow class will look like:

 class SecondRow : public IRow{ FirstRow *_first Q_PROPERTY(FirstRow* first READ _first WRITE _setFirst) public: FirstRow* first() const{ return _first; } void first(FirstRow *first){ _first = first; } private: IRow* _first() const{ return first(); } void _setFirst(IRow *first){ _setFirst(qobject_cast<FirstRow*>(first)); } //... }; 

It works, but the number of setters and getters has doubled.

  • one
    Q_DECLARE and qRegister should not be needed in this case. For the rest, it is strange that it does not work. I do not have 4.8 to check, but in version 5 everything works as it should. - ixSci 1:08
  • @ixSci, maybe this feature appeared in Qt5 QVariant :: value () Qt5 , QVariant :: value () Qt4 - yrHeTaTeJlb
  • Why is not satisfied with the option of converting the value already returned from value ? - αλεχολυτ
  • @ixSci, v.value<void*>() returns 0 . If you write v.value<Foo*>() , then that pointer that I placed there will return. - yrHeTaTeJlb
  • @alexolut, because the class that receives value knows nothing about specific classes. He knows only the base class (interface). And I can’t get the content of value in any way, if I don’t know the real type of this content - yrHeTaTeJlb

2 answers 2

With the data that you have, apparently, the simplest (if not the only) option would be

 QVariant v = QVariant::fromValue(static_cast<void*>(foo)); qDebug() << static_cast<QObject*>(v.value<void*>()); 

You can write wrapper functions for this, which will reduce the amount of code. Something like this:

 QVariant ptrToQVariant(void* ptr) { return QVariant::fromValue(ptr); } QObject* variantPtrToQObject(const QVariant& v) { return static_cast<QObject*>(v.value<void*>()); } 

and then:

 QVariant v = ptrToQVariant(foo); qDebug() << variantPtrToQObject(v); 
  • Yes, I already came to this option. The fact is that I use QVariuant in the context of working with properties. In order to implement this solution, you will have to write two pairs of getters and setters in each class. Some work with normal types, while others work with void* . If there is no better solution, you will have to do just that - yrHeTaTeJlb
  • one
    @yrHeTaTeJlb, can you give an example of a property? I can't understand why you need 2 getters. After all, a solution with void almost indistinguishable from the original version, about which you asked. - ixSci
  • Updated the question. - yrHeTaTeJlb Nov.
  • one
    @yrHeTaTeJlb, unfortunately, by the fact that you brought all the same nothing is clear. There is no QVariant and, frankly, I completely misunderstood your second option. Could you make a minimal example that can be collected and that reflects the entire path of what you are trying to save and load. Otherwise it will be quite difficult to help you with anything. - ixSci
  • Here is a compiled example . QVariant appears when I read property values. - yrHeTaTeJlb

I have this code that works fine on Qt5

myclass.h

 #ifndef MYCLASS_H #define MYCLASS_H #include <QObject> class MyClass : public QObject { Q_OBJECT public: MyClass(){} }; #endif // MYCLASS_H 

main.cpp

 int main(int argc, char *argv[]) { MyClass *someVal = new MyClass(); QVariant var = QVariant::fromValue(someVal); qDebug() << var.value<QObject*>(); //MyClass(0x4bea78) return 0; } 

If for some reason it returns 0. Try registering the converter in the metasystem. To do this, you can use this template function:

 template<class T> void registerToQObjectConverter() { if(!QMetaType::hasRegisteredConverterFunction<T*, QObject*>()) { QMetaType::registerConverter<T*, QObject*>([](T *_value) -> QObject* { return _value; }); } } 

And at the very beginning of the program, add a function:

 registerToQObjectConverter<MyClass>(); 

For all types that will be stored in QVariant

  • But the question is about qt4. - αλεχολυτ
  • Converters were also added in version 5. - ixSci