Domanda

C'è un motivo per cui std::type_info è specificato di essere polimorfici?Il distruttore è specificato essere virtuale (e non c'è un commento per l'effetto di "in modo che è polimorfico" nella Progettazione e nella Evoluzione del C++).Non riesco a vedere un motivo valido.Non ho alcun uso specifico caso, mi stavo chiedendo se mai c'è stata una spiegazione logica o la storia dietro di esso.


Ecco alcune idee che mi è venuta in mente e rifiutato:

  1. È un punto di estensibilità - implementazioni potrebbe definire sottoclassi, e i programmi potrebbero quindi provare a dynamic_cast un std::type_info per un altro, definito dall'implementazione del tipo derivato.Questo è probabilmente il motivo, ma sembra che è facile per le implementazioni di aggiungere un definito dall'implementazione membro, che potrebbe anche essere virtuale.I programmi che desiderano testare queste estensioni, necessariamente, essere non-portatile comunque.
  2. È per garantire che i tipi derivati sono distrutto correttamente quando deleteing base puntatore.Ma non ci sono standard di tipi derivati, gli utenti non possono definire utile tipi derivati, perché type_info non ha standard costruttori pubblici, e così deleteun ing type_info puntatore non è mai legale e portatile.E i tipi derivati non sono utili, perché non può essere costruito - l'unico so che non costruibili tipi derivati nell'attuazione di cose come is_polymorphic tipo di carattere.
  3. Si lascia aperta la possibilità di metaclasses personalizzate tipi di ogni reale polimorfici class A sarebbe un "derivato metaclass" A__type_info, che deriva da type_info.Forse tali classi derivate potrebbe esporre i membri di chiamata new A con vari argomenti del costruttore in un modo type-safe, e cose del genere.Ma fare type_info polimorfici in realtà, rende l'idea sostanzialmente impossibile da attuare, perché avrei dovuto avere metaclasses per il tuo metaclasses, all'infinito, il che è un problema se tutti i type_info gli oggetti hanno la durata di archiviazione statica.Forse escludendo questo è il motivo per polimorfici.
  4. C'è qualche uso per l'applicazione di RTTI caratteristiche (oltre dynamic_cast) per std::type_info di per sé, o qualcuno ha pensato che fosse carino, o imbarazzante se type_info non era polimorfici.Ma dato che non c'è standard tipo derivato, e non le altre classi standard gerarchia che si può ragionevolmente provare croce-cast, la domanda è:cosa????C'è un uso di espressioni come typeid(std::type_info) == typeid(typeid(A))?
  5. È perché gli esecutori potranno creare le proprie privato tipo derivato (come credo GCC fa).Ma perché preoccuparsi di specificarlo?Anche se il distruttore non è stato specificato come il virtuale e l'implementazione deciso che dovrebbe essere, certo che la sua attuazione potrebbe dichiarare virtuale, perché non modificare il set di operazioni consentite su type_info, così un programma portatile non sarebbe in grado di capire la differenza.
  6. E ' qualcosa a che fare con compilatori parzialmente compatibile ABIs coesistenti, forse come risultato di linking dinamico.Forse gli esecutori in grado di riconoscere loro type_info sottoclasse (invece che uno proveniente da un altro fornitore) in modo portatile se type_info è stato garantito virtuale.

L'ultima è la più plausibile per me al momento, ma è piuttosto debole.

È stato utile?

Soluzione

Presumo che c'è per la comodità di realizzatori.Permette di definire estesa type_info classi e li elimina attraverso puntatori a type_info all'uscita dal programma, senza dover costruire speciali compilatore magia per chiamare il corretto distruttore, o altrimenti saltare attraverso i cerchi.

certo che l'attuazione dichiarare virtuale, perché non modificare il set di operazioni consentite su type_info, in modo che un programma portatile non sarebbe in grado di dire la differenza.

Non credo che sia vero.Si consideri il seguente:

#include <typeinfo>

struct A {
    int x;
};

struct B {
    int x;
};

int main() {
    const A *a1 = dynamic_cast<const A*>(&typeid(int));
    B b;
    const A *a2 = dynamic_cast<const A*>(&b);
}

Se è ragionevole o no, il primo cast dinamico è consentita (e restituisce un puntatore null), mentre il secondo cast dinamico non è consentito.Quindi, se type_info è stato definito negli standard predefinita non distruttore virtuale, ma un'implementazione aggiunto un distruttore virtuale, quindi un programma portatile potrebbe dire la differenza[*].

Sembra semplice a me di mettere il distruttore virtuale nella norma, rispetto a:

a) mettere in una nota della norma che, sebbene la definizione di classe implica che type_info non ha funzioni virtuali, si è permesso di avere un distruttore virtuale.

b) determinare l'insieme di programmi che permette di distinguere se type_info è polimorfica o non, e del divieto di tutti.Essi non possono essere molto utili o produttivi di programmi, non so, ma il divieto è necessario venire con un po ' di linguaggio standard che descrive l'eccezione specifica stai facendo le normali regole.

Perciò credo che lo standard sia mandato il distruttore virtuale, o con il bando.Rendendo opzionale è troppo complesso (o forse dovrei dire, penso che sarebbe giudicato inutilmente complesso.La complessità non ha mai smesso, il comitato per gli standard nelle aree in cui si è ritenuto utile...)

Se è stato bannato, però, quindi un'implementazione potrebbe:

  • aggiungi un distruttore virtuale a qualche classe derivata di type_info
  • derivano tutte le sue informazioni sul tipo di oggetti da che classe
  • l'uso che internamente come polimorfici classe di base per tutto

che avrebbe risolto la situazione che ho descritto all'inizio del post, ma il tipo statico di un typeid espressione sarebbe ancora const std::type_info, quindi sarebbe difficile per le implementazioni di definire le estensioni in cui i programmi possono dynamic_cast vari bersagli per vedere che tipo di type_info oggetto che hanno in un caso particolare.Forse lo standard sperava di consentire che, sebbene attuazione potrebbe offrire sempre una variante di typeid con un diverso tipo statico, o la garanzia di un static_cast per una certa classe di estensione funziona, e poi lasciare che il programma dynamic_cast da lì.

In sintesi, per quanto ne so il distruttore virtuale è potenzialmente utile per gli esecutori, e che la sua rimozione non guadagnare nulla di diverso da quello che abbiamo non è possibile passare il tempo a chiedermi perché è lì ;-)

[*] In realtà, non ho dimostrato che.Ho dimostrato che un programma illegale sarebbe, a parità di tutto il resto, per la compilazione.Ma un'implementazione potrebbe forse risolvere tale da garantire che tutti non è sempre uguale, e che non si compila.Aumentare la is_polymorphic non è portatile, così mentre è possibile per un programma di prova che una classe è polimorfici, che dovrebbe essere, non vi può essere alcun modo per un programma conforme al test di una classe non è polimorfici, che non dovrebbe essere.Penso però che anche se è impossibile, dimostrando che, al fine di rimuovere una riga dallo standard, è un bel po ' di sforzo.

Altri suggerimenti

Il C++ standard dice che typeid restituisce un oggetto di tipo type_info, O UN DEFINITO dall'IMPLEMENTAZIONE sottoclasse di esso.Quindi...Credo che questo è più o meno la risposta.Quindi non vedo perché si rifiuta tuoi punti 1 e 2.

Paragrafo 5.2.8 Clausola 1 dell'attuale standard del C++ si legge:

Il risultato di un typeid espressione è un lvalue di tipo statico, const std::type_info (18.5.1) e dinamico tipo const std::type_info o const nome dove il nome è un definito dall'implementazione della classe derivata da std::type_info che conserva il comportamento descritto in 18.5.1.61) La vita dell'oggetto di cui al dal lvalue si estende al fine di il programma.Se o non il distruttore viene chiamato per il type_info oggetto alla fine del programma è non specificato.

Che a sua volta significa che si potrebbe scrivere il seguente codice è legale e fine:const type_info& x = typeid(expr); che possono richiedere che type_info essere polimorfico

Circa il più semplice "globale" id che si può avere in C++ è un nome di classe,e typeinfo fornisce un modo per confrontare tali id per l'uguaglianza.Ma il design è così scomodo e limitato che è quindi necessario avvolgere typeinfo in qualche classe wrapper, ad es.per essere in grado di mettere le istanze raccolte.Andrei Alexandrescu fatto che nel suo "Modern C++ Design" e credo che typeinfo wrapper è parte di Loki biblioteca;probabilmente c'è anche in Spinta;ed è abbastanza facile da arrotolare, ad es.vedere il mio wrapper.

Ma anche per un wrapper non c'è, in generale, qualsiasi necessità di un distruttore virtuale in typeinfo.

La domanda è dunque non tanto "eh, perché c'è un distruttore virtuale", ma, per come la vedo io, "eh, perché il design così indietro, imbarazzante e non direttamente utilizzabile"?E l'ho messa giù per il processo di standardizzazione.Per esempio, iostreams non sono proprio esempi di design superbo, sia;non è qualcosa che si vuole emulare.

3/ lascia aperta la possibilità di metaclasses personalizzate tipi di ogni reale polimorfici class A sarebbe un "derivato metaclass" A__type_info, che deriva da type_info.Forse tali classi derivate potrebbe esporre i membri di chiamata new A con vari argomenti del costruttore in un modo type-safe, e cose del genere.Ma fare type_info polimorfici in realtà, rende l'idea sostanzialmente impossibile da attuare, perché avrei dovuto avere metaclasses per il tuo metaclasses, all'infinito, il che è un problema se tutti i type_info gli oggetti hanno la durata di archiviazione statica.Forse escludendo questo è il motivo per polimorfici.

Intelligente...

Comunque, sono d'accordo con questo ragionamento:tale realizzazione potrebbe facilmente rule-out meta classi per i tipi derivati da type_info, tra cui type_info di per sé.

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