Results 1 to 12 of 12

Thread: Const-Correctness With Q_PROPERTY

  1. #1
    Join Date
    Jan 2010
    Posts
    14
    Thanks
    1
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Const-Correctness With Q_PROPERTY

    I'm trying to develop a class that will be used in a reflection driven application and I ran into an interesting issue that I'm hoping there is a solution to. Let's say I have a class Dummy that has a few properties, one of which is a pointer to another Dummy object:
    Qt Code:
    1. class Dummy : public QObject
    2. {
    3. Q_OBJECT
    4. Q_PROPERTY(int id READ id WRITE setId)
    5. Q_PROPERTY(QObject * child READ child)
    6.  
    7. int myId;
    8. DummyObject *myChild;
    9.  
    10. public:
    11.  
    12. Dummy(int id)
    13. : myId(id), myChild(0)
    14. {
    15. if (myId == 0)
    16. {
    17. myChild = new Dummy(myId + 1);
    18. }
    19. }
    20.  
    21. ~Dummy()
    22. {
    23. delete myChild;
    24. }
    25.  
    26. int id() const
    27. {
    28. return myId;
    29. }
    30.  
    31. void setId(int id)
    32. {
    33. myId = id;
    34. }
    35.  
    36. QObject * child()
    37. {
    38. return myChild;
    39. }
    40.  
    41. };
    To copy to clipboard, switch view to plain text mode 

    And then lets say I create a new Dummy object with id = 0 (so it has one child with id = 1), if I pass the parent Dummy object to a function that takes a constant reference to a QObject (or a constant pointer for that matter), how can I guarantee const-correctness on the child function? I tried the obvious: Q_PROPERTY(const QObject * child READ child) and then making const QObject * child() const (which is really how I want this function to look like), but then the moc complains about: "Unable to handle unregistered datatype 'const QObject*'". I just can't figure out how to make it so that if I pass a constant reference or pointer to a Dummy object that the "child" function (through the qt property system) will expose a constant reference or pointer (to ensure const-correctness).

  2. #2
    Join Date
    Jan 2006
    Location
    Munich, Germany
    Posts
    4,714
    Thanks
    21
    Thanked 418 Times in 411 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows

    Default Re: Const-Correctness With Q_PROPERTY

    The property name and type and the READ function are required. The type can be any type supported by QVariant, or it can be a user-defined type.
    Now look at enum QVariant::Type.
    QObject * is not there.

    Then:
    Custom types used by properties need to be registered using the Q_DECLARE_METATYPE() macro so that their values can be stored in QVariant objects. This makes them suitable for use with both static properties declared using the Q_PROPERTY() macro in class definitions and dynamic properties created at run-time.
    have a look at QVariant qVariantFromValue ( const T & value );.

    One easy way would be to typedef a long as pointer type and convert it in your class back to pointer again.
    ==========================signature=============== ==================
    S.O.L.I.D principles (use them!):
    https://en.wikipedia.org/wiki/SOLID_...iented_design)

    Do you write clean code? - if you are TDD'ing then maybe, if not, your not writing clean code.

  3. #3
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Const-Correctness With Q_PROPERTY

    I'd say that trying to have a static property that holds QObject pointers is a bad idea without even dwelling about whether it works or not. Qt has another facility for holding hierarchies of objects that you should be using here. If you want to hold some reference to the child object then have that property contain a unique id to the child object that can be used to retrieve the real object pointer for the id.

    Something like this should work:
    Qt Code:
    1. class MyObject : public QObject {
    2. Q_OBJECT
    3. Q_PROPERTY(int id READ id WRITE setId)
    4. Q_PROPERTY(int childId READ childId WRITE setChildId)
    5. public:
    6. // ...
    7. void setId(int id) {
    8. if(m_id == id) return;
    9. if(ObjectManager::instance()->hasId(m_id)) {
    10. ObjectManager::instance()->unregister(m_id);
    11. }
    12. if(ObjectManager::instance()->register(id, this)){
    13. m_id = id;
    14. } else {
    15. qWarning("Id %d already taken. Operation failed.", id);
    16. }
    17. }
    18. void setChildId(int id) {
    19. if(id == m_childId) return;
    20. if(!ObjectManager::instance()->hasId(id)){
    21. qWarning("No object with id %d exists. Operation failed.", id);
    22. return;
    23. }
    24. m_childId = id;
    25. }
    26. };
    27.  
    28. // ...
    29.  
    30. QObject* ObjectManager::objectById(int id) const {
    31. return m_objects.value(id, 0);
    32. }
    To copy to clipboard, switch view to plain text mode 

    provided ObjectManager is a singleton handling registration of objects in the system.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  4. #4
    Join Date
    Jan 2010
    Posts
    14
    Thanks
    1
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Const-Correctness With Q_PROPERTY

    Yeah, I mean I can make this work by doing something like:
    Qt Code:
    1. // Split property into tokens and push into queue
    2. QStringList tokens = myProperty.split(QChar('.'));
    3. QQueue<QString> queue;
    4. foreach (QString str, tokens)
    5. {
    6. queue.enqueue(str);
    7. }
    8.  
    9. // Reference object pointer and resolve base properties
    10. const QObject *obj = &object;
    11. while (queue.size() > 1)
    12. {
    13. QString token = queue.dequeue();
    14.  
    15. if (obj->property(token.toLocal8Bit().constData()).canConvert<QObject *>())
    16. {
    17. qDebug() << token;
    18. QObject *obj2 = obj->property(token.toLocal8Bit().constData()).value<QObject *>(); // I don't want this cast to be allowed
    19. obj2->setProperty("id", -2); // because this shouldn't be possible
    20. obj = obj->property(token.toLocal8Bit().constData()).value<QObject *>();
    21. }
    22. }
    23.  
    24. QString prop = queue.dequeue();
    25. qDebug() << prop;
    26. qDebug() << obj->property(prop.toLocal8Bit().constData()).toInt();
    To copy to clipboard, switch view to plain text mode 

    So in this block of code (which I've been working with for testing) I am splitting the property string for the supplied const Dummy reference "object" (in this case myProperty is equal to "child.id") into the respective components and then resolving them on the base object. The output for this code is what I expect:

    "child"
    "id"
    1 (or -2 if the line that shouldn't be allowed is there)
    However, I don't want the two lines that essentially pull a QObject * from the property "child" to be permissible in this function (since obj is a const QObject *). I don't know what to do to the Q_PROPERTY or child function to prevent this.


    Added after 7 minutes:


    wysota:

    Yeah, that was another route I was considering, however, maybe if I put this into context you'll understand what I'm trying to do. Basically, I'm writing a generic logical expression interpreter so that if you want to know if the value of myObject1->propertyA()->propertyB()->propertyC() is greater than 4 (or any value) where myObject1 has a function that exposes another QObject through propertyA(), which then exposes another QObject through propertyB() which has a function called propertyC() that returns an int, you could pass in myObject1 with a property qualitfier of "propertyA.propertyB.propertyC" and a value of 4 (and comparison type), and it could use reflection to dig into the properties to find the final value.

    The goal is to be able to pass any generic object to this type of logic operator and be able to reflect on the desired comparison value (which will always be a QVariant).
    Last edited by Sanuden; 15th November 2010 at 15:48.

  5. #5
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Const-Correctness With Q_PROPERTY

    Quote Originally Posted by Sanuden View Post
    Yeah, that was another route I was considering, however, maybe if I put this into context you'll understand what I'm trying to do. Basically, I'm writing a generic logical expression interpreter so that if you want to know if the value of myObject1->propertyA()->propertyB()->propertyC() is greater than 4 (or any value) where myObject1 has a function that exposes another QObject through propertyA(), which then exposes another QObject through propertyB() which has a function called propertyC() that returns an int, you could pass in myObject1 with a property qualitfier of "propertyA.propertyB.propertyC" and a value of 4 (and comparison type), and it could use reflection to dig into the properties to find the final value.

    The goal is to be able to pass any generic object to this type of logic operator and be able to reflect on the desired comparison value (which will always be a QVariant).
    Well, the problem is this pseudocode immediately crashes your application:

    Qt Code:
    1. QObject *o1 = new QObject;
    2. QObject *o2 = new QObject;
    3. o1->setProperty("child", o2);
    4. delete o2;
    5. o1->property("child")->anything();
    To copy to clipboard, switch view to plain text mode 
    and you don't even know why (value returned by o1->property() is not null).

    What you want to achieve is essentially this (using object names instead of properties):
    Qt Code:
    1. QVariant evaluate(QObject *obj, const QString &expression){
    2. QStringList path = expression.split(".");
    3. QString method = path.last();
    4. path.removeLast();
    5. foreach(QString subobj, path){
    6. obj = obj->findChild<QObject*>(subobj);
    7. if(!obj) return QVariant(); // invalid path
    8. }
    9. // here we have the final object to call the method on.
    10. QMetaMethod meth = obj->metaObject()->method(obj->metaObject()->indexOfMethod(qPrintable(method));
    11. // for string return type:
    12. QString ret;
    13. if(meth.invoke(obj, Q_RETURN_ARG(ret))) {
    14. return ret;
    15. } else {
    16. return QVariant(); // call failed
    17. }
    18. }
    To copy to clipboard, switch view to plain text mode 

    You can do the same with a custom QObject subclass and a custom method if you don't want to use the built-in parent-child relationship. The thing is you should have a single place to control existance of the objects. It will not let you have constness guarantee but I doubt you can have it anyway (you can always cheat the compiler with e.g. a const_cast).
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  6. The following user says thank you to wysota for this useful post:

    Sanuden (15th November 2010)

  7. #6
    Join Date
    Jan 2010
    Posts
    14
    Thanks
    1
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Const-Correctness With Q_PROPERTY

    Yeah, I see where you are going with this. Ideally I would like to have the "child" functions (the ones returning QObjects) to return references to QObjects (thus preventing them from being null, but obviously not preventing the type of failure you indicated). However, at least that way it is probably not a reasonable assumption when you are designing a class that if you have a function return a reference to an object that the reference be valid. That being said, I never considered using the built-in parent-child relationship that Qt exposes. I'm not sure if I'm a tremendous fan of using Qt's built in mechanism (since this is trying to be a generic framework for this type of logic), but at the same time (like you pointed out), it would be easy enough to create my own abstract class to implement this type of logic.

    This begs one final question, is it common practice with QObjects to set up the parent-child relationship for something that just owns another class (like the Dummy class in my example)? I know for Gui concepts it makes a lot of sense (because of the memory management), but for general classes, should this be expected?

    Thanks again.

  8. #7
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Const-Correctness With Q_PROPERTY

    As for most questions the answer is "it depends". Sometimes a parent-child relationship is established (usually if the child needs to access its parent) but in some cases a dynamic property is used (if the helper object should be hidden (or rather obscured) from the outside world). And in some cases there is a dedicated method for registering an object, especially if it can work with many other objects.

    What is the general goal of implementing the mechanism you are trying to create?
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  9. #8
    Join Date
    Jan 2010
    Posts
    14
    Thanks
    1
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Const-Correctness With Q_PROPERTY

    The general goal is the following:

    Be able to create a generic "Logical Expression" mechanism so that one may first initialize a logical expression, consisting of multiple "Logical Conditions" and then provide an appropriate QObject to be evaluated by the expression on the basis of being true or false.

    For example, say I have a class called Car which has a property that is another class called Engine. Now, one particular car instance has a type of "Coupe" and an engine cylinder count of 6, while another might have the type of "SUV" with the engine cylinder count of 6. I'm trying set up the local expression mechanism so that I could filter the cars by saying something like: I want all the cars of type "SUV" with engines with at least 6 cylinders to do something (whatever something may be). The trick (obviously) is that I'm trying to develop the expression mechanism not just to work for cars and engines, but any generic QObject. So, for instance, looking at my earlier posts, this could be represented as: ((Type == "SUV") AND (Engine.CylinderCount >= 6)) if the QObject that was provided was the type Car (hence, Car.Type(), and Car.Engine().CylinderCount()). The idea is to use this is in a plugin library where we want to allow the user freedom to develop logical expressions on their own custom datatypes that inherit from QObject (hence the requirement for reflection).

  10. #9
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Const-Correctness With Q_PROPERTY

    To be honest I would probably use some scripting language (like QtScript) and I would simply expose appropriate properties to the script. I don't really see the benefit of using QObject here anywhere. I think in this situation it is more a burden than a benefit. I don't know if QtScript can directly operate on properties that are QObjects (which is very likely) but even if not, it shouldn't be too hard to add appropriate pieces of code. And you wouldn't be limited to QObjects too. And you would get all the power of JavaScript for free.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  11. #10
    Join Date
    Jan 2010
    Posts
    14
    Thanks
    1
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Const-Correctness With Q_PROPERTY

    Interesting, I hadn't considered that route at all. I've looked into QtScript a bit for some other things I am working on, and now that you mention it, this might be a good fit for this as well. Thanks for the suggestions, I'll play around and see what I can come up with.

  12. #11
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Const-Correctness With Q_PROPERTY

    It seems it works just fine:
    Qt Code:
    1. #include <QtScript>
    2. #include <QtCore>
    3.  
    4. int main(int argc, char **argv){
    5. QCoreApplication app(argc, argv);
    6. QScriptEngine eng;
    7. QObject o1;
    8. QObject o2;
    9. o1.setProperty("child", qVariantFromValue(&o2));
    10. o2.setProperty("val", 7);
    11. QScriptValue o1Obj = eng.newQObject(&o1);
    12. eng.globalObject().setProperty("obj", o1Obj);
    13. qDebug() << eng.evaluate("obj.child.val == 7").toBool();
    14. qDebug() << eng.evaluate("obj.child.val == 8").toBool();
    15. return 0;
    16. }
    To copy to clipboard, switch view to plain text mode 

    Program result:
    true
    false
    To avoid the "obj" property just change the global property of the whole script to your main object (o1Obj). You might want to copy the original object's properties to have access to JS libraries.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  13. #12
    Join Date
    Jan 2010
    Posts
    14
    Thanks
    1
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Const-Correctness With Q_PROPERTY

    Very nice, yeah, I think I can make this do what I want. Thanks for all your help.

Similar Threads

  1. Replies: 1
    Last Post: 4th December 2009, 17:03
  2. const member and const method
    By mickey in forum General Programming
    Replies: 8
    Last Post: 9th April 2008, 09:44
  3. Why and when to use Q_PROPERTY
    By Vanir in forum Qt Programming
    Replies: 4
    Last Post: 22nd November 2007, 09:25
  4. How to Use Q_PROPERTY
    By mitesh_modi in forum Qt Programming
    Replies: 7
    Last Post: 20th June 2006, 14:49
  5. Pointers and Q_PROPERTY
    By andersin in forum Qt Programming
    Replies: 3
    Last Post: 1st March 2006, 14:05

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.