2009-05-12 9 views
12

Ho lavorato per anni con Java. Durante quegli anni, ho fatto un uso estensivo (o forse solo frequente) della riflessione e l'ho trovato utile e piacevole. Ma 8 mesi fa ho cambiato il mio lavoro, e ora Java è solo un ricordo, e sto mettendo le mani su C++. Quindi ora mi chiedo se c'è qualche meccanismo di riflessione in C++. Ho letto di RTTI, ma ritengo che non sia affatto la potenza del reflecion Java (o di altre lingue). Sto iniziando a pensare che non c'è modo di farlo in C++. Ho sbagliato?Reflection in C++

risposta

5

Se siete alla ricerca di un modo del tutto generale per manipolare gli oggetti in fase di esecuzione quando non si conoscono i loro tipi in fase di compilazione in C++, è essenzialmente necessario:

  1. definire un'interfaccia (classe base astratta con tutti i metodi virtuali puri e nessun membro) per ogni funzionalità che una classe potrebbe supportare.
  2. Ogni classe deve ereditare virtualmente da tutte le interfacce che desidera implementare (possibilmente tra le altre classi).

Ora, supponiamo pFoo detiene un puntatore di tipo IFoo* a qualche oggetto x (non è necessario conoscere il tipo di cemento 's x). Si può vedere se questo oggetto supporta un'interfaccia IBar dicendo:

if (IBar* pBar = dynamic_cast<IBar*>(pFoo)) { 
    // Do stuff using pBar here 
    pBar->endWorldHunger(); 
} else { 
    // Object doesn't support the interface: degrade gracefully 
    pFoo->grinStupidly(); 
} 

Questo approccio presuppone che conosciate tutte le interfacce rilevanti in fase di compilazione - se non lo fai, non sarà in grado di utilizzare il normale C++ sintassi per i metodi di chiamata comunque. Ma è difficile immaginare una situazione in cui il programma chiamante non sappia cosa sono le interfacce - circa l'unico caso che posso pensare sarebbe se si desidera esporre oggetti C++ tramite un interprete interattivo. Anche in questo caso, è possibile escogitare un (brutto, intensivo di manutenzione) per archiviare questo nel paradigma precedente, in modo che i metodi possano essere chiamati specificando i loro nomi e argomenti come stringhe.

L'altro aspetto da considerare è la creazione dell'oggetto . Per fare ciò senza conoscere i tipi concreti, avrai bisogno di una funzione di fabbrica, oltre agli identificatori univoci per le classi per specificare quale classe concreta desideri. È possibile organizzare la registrazione delle classi con una fabbrica globale all'avvio, as described here by C++ expert Herb Sutter, evitando di mantenere una gigantesca dichiarazione switch, facilitando notevolmente la manutenzione. È possibile utilizzare un singolo factory, sebbene ciò implichi che esiste un'interfaccia singola che ogni oggetto nel proprio sistema deve implementare (la factory restituirà un puntatore o un riferimento a questo tipo di interfaccia).

Alla fine della giornata, quello che si finisce con è fondamentalmente (isomorfo a) COM-dynamic_cast<IFoo*> fa lo stesso lavoro di QueryInterface(IID_IFoo), e l'interfaccia di base implementata da tutti gli oggetti è equivalente a IUnknown.

1

RTTI è una soluzione (quale parte di Java pensi non sia in RTTI?), Altrimenti puoi implementare il tuo framework di oggetti - lascia che ogni tuo oggetto C++ erediti qualche interfaccia di riflessione, e quindi dovrebbe funzionare.

+1

Penso che la mia conoscenza di RTTI sia scadente ... ma esiste un modo per ottenere un elenco di metodi o attributi di un oggetto utilizzando RTTI? – aitor

+2

@aitor: No, non ci credo. RTTI può indicare il tipo di oggetto in fase di esecuzione, ma è responsabilità dell'utente convertire tali informazioni in informazioni più precise, ad esempio la disponibilità di metodi e attributi. –

+1

Il complesso RTTI può avere questo aspetto: http://www.codeproject.com/KB/library/vcf_rtti.aspx – Francis

15

Poiché lo standard C++ non copre tale concetto come "metadati", non esiste alcun metodo portatile (su diversi compilatori e piattaforme, peraltro) di riflessione del tempo di esecuzione diverso da RTTI già menzionato.

In C++, c'è anche una possibilità di riflessione in fase di compilazione (si pensi a boost::type_traits e boost::type_of), ma è anche limitato rispetto, per esempio, a Nemerle o LISP.

La maggior parte dei framework principali (MFC, Qt, ecc.) Consente di estrarre le metainformazioni in fase di esecuzione, ma richiedono tutti i tipi di annotazioni speciali affinché funzioni (vedere RUNTIME_CLASS e altri come esempio).

0

se tutto ciò che si sta utilizzando è un'iniezione di dipendenza (un'implementazione di qualche interfaccia^H^H^H^H^H^pura classe astratta), si potrebbe provare il caricamento dinamico di file .dll o .so che contengono l'implementazione-of-the-day per qualunque sia la spina.

Probabilmente solo aggrapparsi a cannucce, in quanto ciò non funzionerà bene per molteplici implementazioni di cose allo stesso tempo.

3

È necessario utilizzare il modello di visitatore. Qualsiasi classe su cui è possibile riflettere dovrebbe avere ereditato una classe base che gli ha dato una funzione membro Reflect, che accetta una classe visitatore. Quindi la funzione Reflect passerebbe informazioni o capacità sugli altri membri al visitatore.

Molte librerie popolari utilizzano questo modello per casi specifici, ad esempio, la funzione Serialize in MFC lo fa ma in particolare per la serializzazione.

Probabilmente potresti progettare un sistema in modo tale che il visitatore sia in grado di effettuare chiamate dinamiche alle funzioni membro, ottenere o impostare i valori dei membri dati, ecc. Ma sarebbe responsabilità di ogni classe mantenere una funzione Reflect scritta a mano, che sarebbe una ripetizione della struttura della classe.

1

Reflection è il processo mediante il quale un programma per computer può osservare e modificare la propria struttura e il proprio comportamento. Non vedo come si possa fare il reflection in C++. RTTI è utile solo per il tipo di dati dell'oggetto in memoria in fase di esecuzione.

4

Dai un'occhiata allo my answer to a similar question. Entrambe le soluzioni (XRTTI e OpenC++) proposte sono basate su strumenti esterni che generano i metadati di riflessione per voi durante il processo di compilazione.

0

Che cosa devi fare in C++ e su quale piattaforma stai lavorando? Conosco un modo per ottenere le definizioni di classe complete e invocare funzioni utilizzando questi dati, funziona in Windows ma non conosco altre piattaforme. L'idea è di prendere i dati dalla DLL o dalla tabella di esportazione exe. Non è facile: ci sono voluti diversi mesi di lavoro per ottenere un'implementazione decente, ma farà tutto ciò che fanno i linguaggi di supporto alla riflessione.

+0

cosa significa la tua risposta? dov'è l'implementazione decente di cui parli? –

Problemi correlati