Domanda

Perché, ad esempio, non esiste un supporto linguistico per esaminare una vtable? Perché non posso sostituire una funzione membro con una nuova? Ho la sensazione che ci siano modi per mettere a frutto tali funzionalità.

Ci sono altre lingue là fuori che mi permettono di fare queste cose?

È stato utile?

Soluzione

Il motivo principale è che mantenere vtable come dettaglio di implementazione consente a qualsiasi implementazione concreta di ottimizzarla come meglio ritiene; questo significa che può ad es. tagliare o addirittura eliminare del tutto vtable se può dimostrare che non ci sono chiamate virtuali per un determinato metodo (o tutti i metodi). Oppure può sostituire una spedizione vtable con un controllo del tipo if-else se ad es. vede che ci sono solo poche alternative (questo può essere vantaggioso perché in questo caso la previsione del ramo funzionerà, ma non con vtables, e anche perché i rami if-else possono essere incorporati). Può riordinare i metodi in vtable in modo tale che quelli più comunemente chiamati vengano prima, o tali che quelli che vengono comunemente chiamati uno dopo l'altro riempiono gli slot adiacenti in vtable per sfruttare la memorizzazione nella cache. E così via e così via. Ovviamente, tutte quelle implementazioni renderebbero il layout di vtable del tutto imprevedibile, e quindi inutile, se fosse esposto (secondo le specifiche del linguaggio) all'implementazione.

Inoltre, i vtables non sono così semplici come sembrano. Ad esempio, i compilatori devono spesso generare thunk per correggere questo puntatore a cose come eredità virtuale o eredità multipla combinata con tipi di ritorno covarianti. Questo è ancora qualcosa che non ha un "solo modo migliore". per farlo (motivo per cui diversi compilatori lo fanno in modo diverso) e standardizzarlo richiederebbe effettivamente di stabilirsi in un modo particolare.

Detto questo, "commutazione di tabella". è una tecnica potenzialmente utile se esposta come un costrutto di livello superiore (in modo che le ottimizzazioni siano ancora possibili). Per un esempio, vedere UnrealScript, che consente di definire diversi stati per una classe (uno predefinito, altro nome) e sovrascrive alcuni metodi negli stati con nome. Le classi derivate possono sovrascrivere più metodi negli stati esistenti oppure aggiungere i propri stati e sovrascrivere in essi. Inoltre, gli stati possono estendere altri stati (quindi se un metodo non viene ignorato per uno stato particolare, ricade nello stato "padre" e così via fino a quando la catena raggiunge lo stato predefinito). Per la modellazione di attori (quali sono essenzialmente i giochi), tutto ciò ha molto senso, motivo per cui UnrealScript ce l'ha. E l'ovvio meccanismo di implementazione efficiente per tutto ciò è la commutazione della vtable, con ogni stato con una vtable separata.

Altri suggerimenti

Perché è un dettaglio di implementazione del compilatore. Tale implementazione potrebbe cambiare e qualsiasi codice che si basa su di essa sarebbe nella migliore delle ipotesi fragile.

C ++ è un linguaggio in cui non si "paga" mai per ciò che non si utilizza. Questo tipo di supporto di runtime andrebbe contro questa filosofia.

Esistono molte lingue (all'estremità più dinamica dello spettro) che lo supportano.

Perché non deve essere implementato come VTable , sebbene di solito questo sia il caso. In breve, non esiste qualcosa come VTable in C ++!

JavaScript, Python e Ruby possono farlo tutti. In tali lingue, le definizioni di classe e istanza sono modificabili in fase di esecuzione. In astratto, ogni oggetto e tipo è un dizionario di variabili e metodi membri che possono essere esaminati e aggiornati.

Questo non è possibile in C ++ perché richiederebbe la possibilità di riscrivere il codice binario generato, il che può comportare un notevole costo in termini di prestazioni.

Vtables esiste solo in determinate circostanze in alcuni compilatori (cioè non sono specificati nello standard ma in un dettaglio di implementazione). Anche quando esistono, si verificano solo quando si hanno funzioni virtuali e è necessaria la direzione indiretta per implementare il polimorfismo. Quando ciò non è necessario, possono essere ottimizzati, salvando l'overhead della indiretta sulla chiamata.

Purtroppo (o altrimenti, a seconda delle tue opinioni in merito ;-), C ++ non è stato progettato per supportare il patching delle scimmie. In alcuni casi (ad es. COM) la vtable fa parte dell'implementazione e potresti essere in grado di curiosare dietro le quinte. Tuttavia, questo non sarebbe mai supportato o portatile.

Credo che tu possa fare cose del genere in linguaggi dinamici come Python:

>>> class X():
...     def bar(self): print "bar"
...     
>>> x = X()
>>> x.bar()
bar
>>> def foo(x): print "foo"
... 
>>> X.bar = foo
>>> x.bar()
foo

La differenza con un linguaggio statico come C ++ è che l'interprete cerca tutti i nomi in fase di esecuzione e quindi decide cosa fare.

In C ++ ci sono probabilmente altre soluzioni per sostituire una funzione membro con un'altra "quot" problema, il più semplice dei quali potrebbe utilizzare i puntatori a funzione:

#include <iostream>

class X;
typedef void (*foo_func)(const X&);

void foo(const X&) { std::cout << "foo\n"; }
void bar(const X&) { std::cout << "bar\n"; }

class X
{
    foo_func f;
public:
    X(): f(foo) {}
    void foobar() { f(*this); }
    void switch_function(foo_func new_foo) { f = new_foo; }
};

int main()
{
    X x;
    x.foobar();
    x.switch_function(bar);
    x.foobar();
}

(foo e bar non usano l'argomento X & amp; in questo esempio, simile all'esempio di Python)

Sto lavorando su un linguaggio compilato staticamente che espone la vtable e credetemi è un bel po 'di capelli da esporre.

  • Tutto ciò che puoi fare in C ++, puoi farlo in C dritto con un po 'di grasso per gomiti.
  • Qualsiasi programma C modesto e ragionevole dovrebbe essere compilato in C ++.

Forse quello che vuoi è implementare i tuoi vtables senza usare la funzione integrata di C ++. Ti divertirai molto con le funzioni da puntatore a membro (ptmf)!

Avrai difficoltà a trovare un linguaggio compilato con introspezione di vtable perché c'è poca richiesta e non è facile da implementare. Per le lingue interpretate, tuttavia, la situazione è al contrario.

  

Esistono altre lingue   lì che mi permettono di farlo   cose?

Objective-C (e anche Objective-C ++) consente la sostituzione di runtime di metodi già compilati. È la migliore combinazione di tecniche statiche e dinamiche o la peggiore, a seconda di chi chiedi.

Come altri hanno sottolineato, non esiste un concetto di "vtable" nello standard C ++, in quanto è solo una tecnica di implementazione quasi universale, molto simile alla manipolazione dei nomi.

Se stai cercando di essere in grado di ridefinire le funzioni al volo in un linguaggio compilato, potresti essere interessato a Common Lisp. Devono essercene altri, ma le uniche altre lingue a cui riesco a pensare hanno ereditarietà e funzioni statiche o sono interpretate a un costo elevato in termini di prestazioni.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top