There are two problems:
A trivial one: the lack of object dereference elsewhere in your code - a typo.
The meta object compiler (moc) does not support nested classes. Your code will compile, but it won't pass the moc step, with the following error:
Error: Meta object features not supported for nested classes
I do commend you for not prematurely pessimizing the storage of wid1
and wid2
. You stored them by value - as you should. Ideally, though, you should store all such objects by value - not only the two sub-dials. It will also make things easier to read to decouple the instantiation of the inner classes from their declaration.
So, the sub-dial types need to be moved out of the class. You can put them in a namespace so that they don't pollute the global one.
namespace UDial_ {
class CUDial : public QWidget {
Q_OBJECT
public:
CUDial(QWidget *parent = 0) : QWidget(parent) {}
};
class DUDial : public QWidget
{
Q_OBJECT
public:
DUDial(QWidget *parent = 0) : QWidget(parent) {}
};
}
Secondly, once you do store objects by value, the children must be declared after the parents. This is because the compiler will generate code to destruct them in the reverse order of declaration. The child QObject
s must be destroyed before the parents, otherwise the parents will, incorrectly, attempt to delete
them.
I don't know of any way to force the compiler to enforce this without changing Qt source code, but you can at least indicate your intent by using the C++11 value initialization.
class UDial : public QDialog
{
Q_OBJECT
QVBoxLayout vlay { this }
QTabWidget tab;
// We make it explicit that both sub-dials are children of tab and must not
// be declared / initialized before it!
UDial_::CUDial wid1 { &tab };
UDial_::DUDial wid2 { &tab };
QDialogButtonBox box;
public:
UDial(QWidget *parent = 0);
};
Unfortunately, the compiler will at best emit a warning if we do the wrong thing, although any decent static analyzer will loudly complain about it, of course.
class UDial : public QDialog
{
Q_OBJECT
QVBoxLayout vlay { this };
UDial_::CUDial wid1 { &tab };
UDial_::DUDial wid2 { &tab };
QTabWidget tab; // WRONG, comes after the use above
QDialogButtonBox box;
public:
UDial(QWidget *parent = 0);
};
This code will, in most cases, crash upon startup, but that's not a crash we can depend on - say, as if we dereferenced a nullptr
. But beware: the compiler is free to optimize out any dereferences of a nullptr
!
The constructor will then look similar to:
UDial::UDial(QWidget * parent) :
QDialog(parent),
box(QDialogButtonBox::Ok | QDialogButtonBox::Cancel)
{
vlay.addWidget(&tab);
vlay.addWidget(&box);
tab.addTab(&wid1, "Dial 1");
tab.addTab(&wid2, "Dial 2");
}
If you're using an older compiler that doesn't support C++11 value initialization, you cannot use the brace initialization syntax, and you are forced to declare your intent in the constructor - where it is more likely to be ignored by an unwitting maintainer:
UDial::UDial(QWidget * parent) :
QDialog(parent),
vlay(this),
wid1(&tab), wid2(&tab),
box(QDialogButtonBox::Ok | QDialogButtonBox::Cancel)
{ ...
BartoszKP has a valid argument that since the checking of this cannot be reliably relegated to compile time, there is some merit to explicitly allocating all sub-objects on the heap, and letting Qt deal with proper destruction order at run-time. While I personally haven't run into any problems related to that, I'm very diligent and in a privileged position of having me and myself to maintain my code base. In larger projects that are not managed with proper process documentation in place to point out such procedural details, this approach may lead to errors. Such errors are, IMHO, more of an indication of a procedural issue in the development process than the validity of the approach. It then becomes a premature pessimization to work around development process deficiencies. It's up to you to decide whether that's a valid tradeoff. I personally cringe when I see the result of new
assigned to a raw pointer - it tends to desensitize one to such incorrect uses where you don't have a nice memory-managing class like QObject
.