Search code examples
c++qtexplicit-constructor

Why can I assign a QObject* to a QObject?


Consider the following code:

#include <QObject>

class A : public QObject
{
    Q_OBJECT
    public: 
        A(QObject* parent = 0) : QObject(parent) {}
}

int main()
{
    A a = new A();
    return 0;
}

Why can I assign an object of type A* to a variable of type A without the compiler (or runtime) complaining?


Solution

  • In this code, the constructor of A is used to convert an A* to an object of type A, instead of assigning it. In general the compiler is allowed to implicitly use a matching constructor as a conversion operator, so that the following is legal code:

    struct B
    {
        B(int i){}
    }
    int main()
    {
        B b = 5;
        return 0;
    }
    

    In the code of the question, the unnamed A* that results from the new operator is used as the parent argument of the constructor of A. This is allowed since A is derived from QObject (and thus matches the argument list). However, this is clearly undesired behaviour because a is not the object returned by new, but an object of type A parented to that object. (In addition, the new'ed object is never deleted, resulting in a memory leak.)

    To prevent this kind of subtle error, it is generally advised to make the constructor of QObject-derived classes explicit to prevent the compiler from mis-using it as a conversion operator. (This applies to similar situations too, not only to Qt.) With the following modified code, the compiler will catch the error:

    class A : public QObject
    {
        Q_OBJECT
        public: 
            explicit A(QObject* parent = 0) : QObject(parent) {}
    }