Making default constructor private in QT custom object

It has to do with QVariant's (templated) implementation.

Look at qvariant.h in the QT5.5 source code tree, and you'll find this:

       T t;
       if (v.convert(vid, &t))
            return t;
       return T();

And also:

       old->~T();
       new (old) T(t); //call the copy constructor

Hence the need for a public constructor/desctructor, and copy-constructor.


The advantage of all of this is being able to use your custom type in signals/slots (and other meta-object magic), but there are drawbacks like in your situation. It's just a trade-off that you have to live with.

As a workaround, you could have some sort of "init()" method that actually initializes the object after it's constructed. Not as safe/elegant, but it works.


There are two parts to the question:

  1. Achieving a custom Meta Object without implementing a default ctor.
  2. Understanding why a default ctor is required by Qt in this case.

Other respondents have addressed (2) already.

I wish to address (1).

I wrote a class, and I intend for users of this class to call a ctor I wrote which requires several arguments. However, because of the Qt-related requirements, I am forced to add a zero-argument constructor.

It would make me happy to at least make the zero-arg ctor private, so that I could enforce that all user code EXCEPT moc-generated "magic" code will be barred from using that ctor.

Hello, happiness! It is possible.

You can indeed use friendship to make the default ctor private and still use Qt Metatype.

It looks something like this:

class MyClass {
  Q_GADGET

  Q_PROPERTY(QString text READ text)

 public:
  MyClass(QString text, bool sometruth, int someint);

  QString text() const { return text_; }

 private:
  // Works in my project using Qt 5.12. (see hints below if it fails for you)
  friend struct QtMetaTypePrivate::QMetaTypeFunctionHelper<MyClass, true>;
  // Prefer the ctor that takes arguments. This ctor only exists to satisfy Qt.
  MyClass();

  QString text_;
};

There are two ways you can solve the problem of figuring out WHAT to befriend.

You can mark the ctor private, try to recompile, and scrutinize the compiler error to figure out what other type is trying to access the ctor of your class.

Or, you can put an assert(false); in the body of your ctor, create a binary with debug symbols (including Qt debug symbols), then look at the stack in the debugger when the assertion fails. The stack will show the Qt-internal member-function or free function that called into your ctor. Friend whatever that caller is.

This last method (using the debugger) is what worked for me. (I wasn't fluent enough in compiler-ese to discern which type from the output of the gigantic compiler error was what I needed to add as my friend.)