Dear Readers!

This time I’ll keep this post very short, and as such I’ll start with an excerpt from the current C++17 standard

§13.1:
The order of derivation is not significant except as specified by the semantics of initialization by constructor (15.6.2) , cleanup (15.4) , and storage layout (12.2, 14.1).

By reading this (and leaving the cited paragraphs out), on could quickly assume, that deriving from multiple classes can mostly be done in any order, and only in some rate, exotic cases will the order cause problems. This assumption is not really far off I think, but recently I encountered a situation where the order actually did matter, and the compiler wasn’t extremely helpful either to help me figure out what exactly was the problem. This is what I did initially:

C++

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// beatmodel.h

namespace DJApp {

class BeatModelInterface
{
    // interface stuff
};

class BeatModel : public BeatModelInterface, public QObject
{
    Q_OBJECT
public:
    // class stuff

private:
    // additional class stuff
};

} // DJApp

I guess, to a lot of people this would seem to be a valid class declaration and so it did to me. Unfortunately, the compiler disagrees:

Make

1
2
3
4
5
6
7
8
9
10
11
12
13
moc_beatmodel.cpp:66:28: error: ‘staticMetaObject’ is not a member of ‘DJApp::BeatModelInterface’
     { &BeatModelInterface::staticMetaObject, qt_meta_stringdata_DJApp__BeatModel.data,
                            ^~~~~~~~~~~~~~~~
moc_beatmodel.cpp: In member function ‘virtual void* DJApp::BeatModel::qt_metacast(const char*)’:
moc_beatmodel.cpp:83:32: error: ‘qt_metacast’ is not a member of ‘DJApp::BeatModelInterface’
     return BeatModelInterface::qt_metacast(_clname);
                                ^~~~~~~~~~~
moc_beatmodel.cpp: In member function ‘virtual int DJApp::BeatModel::qt_metacall(QMetaObject::Call, int, void**)’:
moc_beatmodel.cpp:88:31: error: ‘qt_metacall’ is not a member of ‘DJApp::BeatModelInterface’
     _id = BeatModelInterface::qt_metacall(_c, _id, _a);
                               ^~~~~~~~~~~
make: *** [Makefile:838: moc_beatmodel.o] Error 1
21:51:58: The process "/usr/bin/make" exited with code 2.

Hmmm… That ’staticMetaObject’, ’qt_metacast’ and ’qt_metacall’ are not a member of ‘DJApp::BeatModelInterface’. Well, of course they are not, as I didn’t put anything like these into my interface class. But why is it looking for these in there? Obviously, these are Qt related things, and ought to be connected to QObject, which I also derived from, thus it should work. At least that’s the theory. After doing some search on stackoverflow however, I finally found out that the order of derivation does matter, so I made the necessary adjustments:

C++

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// beatmodel.h

namespace DJApp {

class BeatModelInterface
{
    // interface stuff
};

class BeatModel : public QObject, public BeatModelInterface
{
    Q_OBJECT
public:
    // class stuff

private:
    // additional class stuff
};

} // DJApp

No more error messages after this. I’m not exactly sure at this point which rule in the standard determines when and how the order makes a difference, but it seems there are exceptions to the above excerpt, and as such today’s lesson is:

Don’t rely too much on the neutrality rule of derivation. Sometimes the order does matter and the compiler will not help too much in identifying this problem.