Non sono d'accordo con @sechastain
.
Inlining è lungi dall'essere automatico. Indipendentemente dal fatto che il metodo sia definito in posizione o un suggerimento (inline
parola chiave o __forceinline
), il compilatore è l'unico a decidere se l'inlining avrà effettivamente luogo e utilizza euristiche complicate per farlo. Un caso particolare, tuttavia, è che non deve effettuare la chiamata in linea quando viene invocato un metodo virtuale utilizzando la distribuzione runtime, proprio perché la distribuzione e l'inlining del runtime non sono compatibili.
Per comprendere la precisione di "usare runtime spedizione":
IClassInterface* i = /**/;
i->LOL(); // runtime dispatch
i->QueueClass::LOL(); // compile time dispatch, inline is possible
@0xDEAD BEEF
: Trovo il vostro disegno fragile per non dire altro.
L'uso di C-Style getta qui è sbagliato:
QueueClass* p = /**/;
IClassInterface* q = p;
assert(((void*)p) == ((void*)q)); // may fire or not...
Fondamentalmente non v'è alcuna garanzia che i 2 indirizzi sono uguali: si tratta di implementazione definita, ed è improbabile che resistere al cambiamento.
vi auguro di essere in grado di lanciare in modo sicuro il puntatore void*
a un puntatore IClassInterface*
allora avete bisogno di creare da una IClassInterface*
in origine in modo che il compilatore C++ può eseguire il corretto l'aritmetica dei puntatori a seconda della disposizione degli oggetti.
Naturalmente, sottolineerò anche l'uso di variabili globali ... probabilmente lo sapete.
Per quanto riguarda la ragione dell'assenza? Onestamente non vedo nulla a parte un bug nel compilatore/linker. Ho visto la definizione inline delle funzioni virtual
un paio di volte (in particolare, il metodo clone
) e non ha mai causato problemi.
EDIT: Dal momento che "corretta l'aritmetica dei puntatori" non è stato così ben compreso, ecco un esempio
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;
}
Ed ecco ciò che è stato stampato:
Base1: 0x7fbfffee60
Base2: 0x7fbfffee61
Derived: 0x7fbfffee60
Non è la differenza tra il valore di b2
e &d
, anche se si riferiscono a un'entità. Questo può essere compreso se si pensa al layout di memoria dell'oggetto.
Derived
Base1 Base2
+-------+-------+
| mDum1 | mDum2 |
+-------+-------+
Quando la conversione da Derived*
al Base2*
, il compilatore eseguire le regolazioni necessarie (qui, incrementare l'indirizzo puntatore un byte) in modo che il puntatore finisce efficacemente indicando la Base2
parte di Derived
e non al Base1
parte erroneamente interpretata come un oggetto Base2
(che sarebbe sgradevole).
Questo è il motivo per cui è necessario evitare l'uso di trasmissioni in stile C durante il downcasting. Qui, se hai un puntatore Base2
non puoi reinterpretarlo come puntatore Derived
. Invece, sarà necessario utilizzare static_cast<Derived*>(b2)
che decrementerà il puntatore di un byte in modo che punti correttamente all'inizio dell'oggetto Derived
.
I puntatori di manipolazione vengono in genere definiti come aritmetica del puntatore. Qui il compilatore eseguirà automaticamente la regolazione corretta ... alla condizione di essere a conoscenza del tipo.
Sfortunatamente il compilatore non può eseguirli durante la conversione da un void*
, è quindi compito dello sviluppatore assicurarsi che lo gestisca correttamente. La semplice regola empirica è la seguente: T* -> void* -> T*
con lo stesso tipo che appare su entrambi i lati.
Pertanto, è necessario (semplicemente) correggere il codice dichiarando: IClassInterface* globalMember
e non si avrebbe alcun problema di portabilità. Probabilmente avrai ancora problemi di manutenzione, ma questo è il problema dell'uso di C con codice OO: C non è a conoscenza di alcuna roba orientata agli oggetti in corso.
E le altre funzioni virtuali non inline in 'QueueClass' (se ce ne sono)? Lavorano? In altre parole, il problema con 'LOL' local a' LOL's vtable o è l'intero vtable vuoto o mancante? – AnT
perché privatamente ereditare da IClassInterface? –
Perché la funzione 'get ...' restituisce 'void * 'invece di' IClassInterface * '? – AnT