Domanda

http://en.wikipedia.org/wiki/Typeid

Questo sembra essere un mistero per me: come fa un compilatore memorizza informazioni circa il tipo di un oggetto? Fondamentalmente una classe vuota, una volta istanziata, non ha un formato zero nella memoria.

È stato utile?

Soluzione

Come viene memorizzato è definito dall'implementazione. Ci sono molti modi completamente diversi per farlo.

Tuttavia, per i tipi non polimorfici non deve essere conservato. Per i tipi non-polimorfici typeid restituisce informazioni sul static tipo dell'espressione, vale a dire la sua in fase di compilazione tipo. Il tipo è sempre è noto al momento della compilazione, quindi non c'è necessità di associare ogni informazione aggiuntiva oggetti specifici (come per sizeof di lavorare non si ha realmente bisogno di memorizzare le dimensioni in qualsiasi oggetto). "Un oggetto vuoto" che si parla nella sua domanda sarebbe un oggetto di tipo non-polimorfa, quindi non c'è alcuna necessità di memorizzare qualsiasi cosa in esso e non c'è alcun problema con esso avere dimensioni pari a zero. (Nel frattempo, gli oggetti polimorfici sono mai veramente "vuoto" e non hanno mai "taglia zero in memoria".)

Per i tipi polimorfici typeid effettivamente restituisce le informazioni sulla dinamica tipo dell'espressione, cioè sulla sua run-time tipo. Per implementare questo qualcosa deve essere memorizzato all'interno dell'oggetto reale in fase di esecuzione. Come detto in precedenza, diversi compilatori implementano in modo diverso. In MSVC ++, per un esempio, il puntatore VMT memorizzato in ogni punto oggetto polimorfici ad una struttura di dati che contiene il cosiddetto RTTI - runtime informazioni sul tipo di oggetto - oltre alla effettiva VMT

.

Il fatto che si parla di oggetti a zero dimensioni in tua domanda probabilmente indica che avete alcune idee sbagliate su ciò che typeid può e non può fare. Ricordate, nuovamente, typeid è in grado di determinare la (cioè dinamico) tipo di oggetto effettivo per tipi polimorfici solo . Per i tipi non polimorfici typeid non può determinare il tipo effettivo dell'oggetto e ripristina la funzionalità primitiva fase di compilazione.

Altri suggerimenti

Immaginate ogni classe come se si ha questo metodo virtuale, ma solo se si ha già un altro virtuale e un oggetto viene creato per ogni tipo:

extern std::type_info __Example_info;
struct Example {
  virtual std::type_info const& __typeid() const {
    return __Example_info;
  }
};
// "__" used to create reserved names in this pseudo-implementation

Poi immaginare qualsiasi uso di typeid su un oggetto, typeid(obj), diventa obj.__typeid(). Uso su puntatori diventa simile pointer->__typeid(). Tranne per l'uso su puntatori nulli (che getta bad_typeid), il caso puntatore è identico al caso non-pointer dopo dereferenziazione, e non citerò ulteriormente. Quando viene applicato direttamente su un tipo, immaginare che il compilatore inserisce un riferimento direttamente all'oggetto richiesto. typeid(Example) diventa __Example_info

Se una classe non ha RTTI (cioè non ha virtuals; esempio NoRTTI sotto), poi immaginate con un identico __ typeid che è non virtuale. Questo permette la stessa trasformazione in chiamate di metodo come sopra, affidandosi alla spedizione virtuale o non virtuale di tali metodi appropriati; permette anche alcune chiamate a metodi virtuali necessari per essere trasformate in consegna non virtuale, come può essere effettuata per qualsiasi metodo virtuale.

struct NoRTTI {};  // a hierarchy can mix RTTI and no-RTTI, just as use of
                   // virtual methods can be in a derived class even if the base
                   // doesn't contain any
struct A : NoRTTI { virtual ~A(); };  // one virtual required for RTTI
struct B : A {};  // ~B is virtual through inheritance

void typeid_with_rtti(A &a, B &b) {
  typeid(a); typeid(b);
  A local_a;  // no RTTI required: typeid(local_a);
  B local_b;  // no RTTI required: typeid(local_b);

  A &ref = local_b;
  // no RTTI required, if the compiler is smart enough: typeid(ref)
}

Qui, typeid deve utilizzare RTTI per entrambi i parametri (B potrebbe essere una classe base per un tipo più tardi), ma non ha bisogno RTTI per entrambi variabile locale perché il tipo dinamico (o "tipo di runtime ") è assolutamente noto. Questo le partite, non a caso, come le chiamate virtuali possono evitare la spedizione virtuale.

struct StillNoRTTI : NoRTTI {};

void typeid_without_rtti(NoRTTI &obj) {
  typeid(obj);
  StillNoRTTI derived; typeid(derived);
  NoRTTI &ref = derived; typeid(ref);

  // typeid on types never uses RTTI:
  typeid(A); typeid(B); typeid(NoRTTI); typeid(StillNoRTTI);
}

Qui, l'uso su entrambi i obj o ref corrisponderà a NoRTTI! Questo è vero anche se il primo può essere di una classe derivata ( obj potrebbe davvero essere un'istanza di a o B ) e anche se ref è sicuramente di una classe derivata . Tutti gli altri usi (l'ultima linea della funzione) sarà risolto staticamente.

Si noti che in queste funzioni di esempio, ogni typeid utilizza RTTI o meno come suggerisce il nome della funzione. (da qui l'usi commentati-out in with_rtti .)

Anche quando non si utilizza le informazioni sul tipo, una classe vuota non avrà zero byte, ha sempre qualcosa, se non ricordo corrette le richieste standard.

Credo che il typeid viene implementato simile a un puntatore vtable, l'oggetto avrà un puntatore "nascosta" per la sua typeid.

Ci sono diverse domande nella vostra una domanda.

oggetti in C ++ è qualcosa che occupa la memoria. Se non occupa memoria - non è un oggetto (sebbene classe base sub-oggetto può occupare spazio). Quindi, un oggetto deve occupare almeno 1 byte.

Un compilatore non memorizzare tutte le informazioni di tipo a meno che la vostra classe ha una funzione virtuale. In tal caso, un puntatore all'informazione tipo è spesso memorizzato in un offset nella tabella di funzione virtuale negativo. Si noti che la norma non menziona alcuna tabella virtuali o tipo di formato informazioni in modo che è puramente un dettaglio di implementazione.

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