Liebe Leserinnen, liebe Leser,

dieses Mal plane ich nur einen kurzen Beitrag zu schreiben, und deswegen werde ich mit einem Ausschnitt aus dem derzeitigen C++17 Standard beginnen.

§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).

Wenn man das liest (ohne die zitierten Absätze), könnte man das behaupten, dass die Abstellung aus mehreren Klassen in beliebiger Reihenfolge gemacht werden kann, und die Reihenfolge wird nur selten und in exotischen Fällen Probleme verursachen. Meiner Meinung nach ist diese Annahme nicht zu weit hergeholt, aber vor Kurzem habe ich eine Situation begegnet, bei dem die Reihenfolge der Abteilung wirklich wichtig war, und der Compiler war nicht außerordentlich hilfreich bei der Fehlersuche. Das Folgende habe ich ursprünglich gemacht:

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

Ich nehme das an, dass es für viele Leute wie eine gute Klassendeklaration scheinen würde, und ich habe so auch gedacht. Leider stimmt der Compiler nicht zu:

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… Diese ’staticMetaObject’, ’qt_metacast’ und ’qt_metacall’ sind nicht Mitglieder der ‘DJApp::BeatModelInterface’ Klasse. Natürlich sind sie nicht, weil ich solche Sachen in meiner Interface-Klasse nicht geschrieben habe. Warum sucht es dann danach? Diese sind Qt-bezogene Sachen, und sie sollen mit QObject verbunden sein (von dem die Klasse auch abgeleitet ist), also das soll funktionieren. Das ist die Theorie. Nachdem ich stackoverflow dennoch befragt habe, habe ich das endlich herausgefunden, dass die Reihenfolge der Klassenableitung wichtig ist. Deswegen habe einige Änderungen gemacht:

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

Keine mehr Fehlermeldungen treten nach diesen Änderungen auf. Ich bin darüber nicht sicher, welche Regeln in dem Standard die Reihenfolge feststellen, aber es würde so erscheinen, dass es Ausnahmen von dem obengenannten Ausschnitt geben. Also, die Lektion des Tages ist:

Man sollte sich auf den Neutralitätregel nicht zu stark verlassen. Es gibt Fälle, wenn die Reihenfolge wichtig ist, und der Compiler wird bei der Bestimmung des Problems nicht zu viel helfen.