Ich stimme nicht mit @sechastain
.
Inlining ist weit davon entfernt, automatisch zu sein. Unabhängig davon, ob die Methode an Ort und Stelle definiert ist oder ein Hinweis (inline
Schlüsselwort oder __forceinline
) verwendet wird, entscheidet der Compiler als einziger, ob das Inlining tatsächlich stattfindet, und verwendet dafür komplizierte Heuristiken. Ein besonderer Fall ist jedoch, dass ein Aufruf nicht inline ist, wenn eine virtuelle Methode mit dem Laufzeit-Dispatch aufgerufen wird, gerade weil Runtime-Dispatch und Inlining nicht kompatibel sind.
Um die Genauigkeit der "mit Laufzeit Dispatch" zu verstehen:
IClassInterface* i = /**/;
i->LOL(); // runtime dispatch
i->QueueClass::LOL(); // compile time dispatch, inline is possible
@0xDEAD BEEF
: Ich habe Ihr Design spröde finden, gelinde gesagt.
Die Verwendung von C-Casts ist hier falsch:
QueueClass* p = /**/;
IClassInterface* q = p;
assert(((void*)p) == ((void*)q)); // may fire or not...
Grundsätzlich gibt es keine Garantie, dass die 2-Adressen sind gleich: Es ist Implementierung definiert, und es ist unwahrscheinlich Änderung zu widerstehen.
Ich wünschen Sie in der Lage sein, sicher die void*
Zeiger auf einen IClassInterface*
Zeiger zu werfen, dann müssen Sie es von einer ursprünglich IClassInterface*
schaffen, so dass die C++ Compiler die richtigen Zeigerarithmetik auf dem Layout der Objekte in Abhängigkeit führen kann.
Natürlich, ich werde auch unterstreichen als die Verwendung von globalen Variablen ... Sie wissen es wahrscheinlich.
Wie für den Grund der Abwesenheit? Ich sehe ehrlich gesagt nichts außer einem Fehler im Compiler/Linker. Ich habe inline Definition von virtual
Funktionen ein paar Mal gesehen (genauer gesagt, die clone
Methode) und es hat nie Probleme verursacht.
EDIT: Da "richtige Zeigerarithmetik" wurde hier nicht so gut verstanden, ist ein Beispiel
struct Base1 { char mDum1; };
struct Base2 { char mDum2; };
struct Derived: Base1, Base2 {};
int main(int argc, char* argv[])
{
Derived d;
Base1* b1 = &d;
Base2* b2 = &d;
std::cout << "Base1: " << b1
<< "\nBase2: " << b2
<< "\nDerived: " << &d << std::endl;
return 0;
}
Und hier ist, was gedruckt wurde:
Base1: 0x7fbfffee60
Base2: 0x7fbfffee61
Derived: 0x7fbfffee60
nicht der Unterschied zwischen dem
Wert von
b2
und
&d
, obwohl sie sich auf eine Entität beziehen. Dies kann verstanden werden, wenn man an das Speicherlayout des Objekts denkt.
Derived
Base1 Base2
+-------+-------+
| mDum1 | mDum2 |
+-------+-------+
Wenn man von Derived*
zu Base2*
Umwandlung wird der Compiler die notwendige Einstellung durchführen (hier inkrementieren die Zeigeradresse um ein Byte), so dass der Zeiger effektiv Zeige endet bis zum Base2
Teil Derived
und nicht auf die Base1
Teil fälschlicherweise als Base2
Objekt interpretiert (was wäre böse).
Aus diesem Grund ist die Verwendung von C-Style-Modellen beim Downcasting zu vermeiden. Hier, wenn Sie einen Base2
Zeiger haben, können Sie es nicht als Derived
Zeiger neu interpretieren. Stattdessen müssen Sie die static_cast<Derived*>(b2)
verwenden, die den Zeiger um ein Byte dekrementiert, so dass es korrekt auf den Anfang des Derived
Objekts zeigt.
Das Bearbeiten von Zeigern wird normalerweise als Zeigerarithmetik bezeichnet. Hier führt der Compiler automatisch die richtige Anpassung durch ... unter der Bedingung, dass er den Typ kennt.
Leider kann der Compiler sie beim Konvertieren von void*
nicht ausführen, es liegt also am Entwickler, dafür zu sorgen, dass er das richtig handhabt. Die einfache Faustregel ist folgende: T* -> void* -> T*
mit dem gleichen Typ auf beiden Seiten erscheinen.
Daher sollten Sie (einfach) Ihren Code korrigieren, indem Sie Folgendes deklarieren: IClassInterface* globalMember
und Sie hätten kein Portabilitätsproblem. Sie werden wahrscheinlich immer noch ein Wartungsproblem haben, aber das ist das Problem der Verwendung von C mit OO-Code: C ist sich nicht bewusst, dass irgendwelche objektorientierten Dinge passieren.
Was ist mit anderen nicht-inline virtuellen Funktionen in 'QueueClass' (wenn es welche gibt)? Arbeiten Sie? Mit anderen Worten, ist das Problem mit 'LOL' lokal zu' LOL's Vtable-Eintrag oder ist die gesamte Vtable leer oder fehlt? – AnT
warum privat von IClassInterface erben? –
Warum gibt die 'get ...' Funktion 'void *' anstelle von 'IClassInterface *' zurück? – AnT