2010-03-31 1 views
7

Ho una classe C++ che voglio ispezionare. Quindi, mi piacerebbe che tutti i metodi stampino i loro parametri e il ritorno, appena prima di uscire.Esecuzione di un determinato codice per ogni chiamata di metodo in C++

Quest'ultimo aspetto è piuttosto semplice. Se faccio ritorno() per tutto, una macro

#define return(a) cout << (a) << endl; return (a) 

sarebbe farlo (potrebbe essere sbagliato) se padronize tutti i ritorni a tra parentesi (o qualsiasi altra cosa questo può essere chiamato). Se voglio tirarlo fuori, basta commentare il definire.

Tuttavia, gli input di stampa sembrano più difficili. C'è un modo per farlo, usando le strutture C++ o con un workaroud hack?

+4

C'è qualche ragione per cui non puoi semplicemente usare un debugger? – tloach

+0

Sì, voglio inviare input e output a un file per lavorare sui dati. Non voglio eseguire il debug del metodo, è apparentemente corretto e ben testato. –

risposta

4

Tuttavia, gli input di stampa sembrano più difficili. C'è un modo per farlo, usando strutture C++ o con un workaroud hack ?

No.


Aggiornamento: ho intenzione di perdere un po 'concisione nella mia risposta suggerendo che probabilmente si può ottenere quello che ti serve applicando Design by Contract.

+2

Breve, dolce, al punto, corretto. +1. –

2

Sembra che tu voglia utilizzare un'utilità di debug per me. Questo ti permetterà di vedere tutti i parametri che vuoi.

+0

Non voglio vedere i parametri. Voglio produrli tutti per fare qualcosa di diverso, come uno studio statistico, ecc., Che non fa parte dell'utilità. –

1

Se i tuoi metodi sono tutti virtual, è possibile utilizzare lo decorator-pattern per ottenerlo in un modo molto elegante.

MODIFICA: Dal tuo commento sopra (vuoi l'output per le statistiche) Concludo che dovresti assolutamente usare il modello decoratore. È inteso per questo genere di cose.

+0

La sottoclasse otterrebbe lo stesso in questa situazione, vero? Comunque non è quello che sto cercando! Sia la decorazione che la sottoclasse richiederebbero la stessa quantità di codice da scrivere rispetto al trucco sporco (mettendo le stampe ovunque). Tuttavia, dovrei anche cambiare il codice del chiamante. –

+0

Bene, nel tuo profilo si dice che ti piace il buon design ... Purtroppo, l'implementazione di schemi di progettazione in C++ ha sempre un buon numero di piastre di caldaia, ma ha comunque il vantaggio di un'elevata flessibilità. –

+0

Sì, mi piacciono molto i modelli di design, GoF è l'unico libro che si trova sempre al mio tavolo. Ma penso che per questo caso sia eccessivo. Voglio un'abilità temporanea di "accensione/spegnimento" a scopo di sviluppo. –

8

Alcune opzioni vengono in mente:

  • utilizza un debugger.
  • Utilizzare decorator pattern come suggerito da Space_C0wb0y. Tuttavia, questo potrebbe essere un sacco di digitazione manuale, dal momento che dovresti duplicare tutti i metodi nella classe decorata e aggiungere la registrazione da solo. Forse potresti automatizzare la creazione dell'oggetto decoratore eseguendo Doxygen sulla tua classe e poi analizzandone l'output ...
  • Utilizzare aspect-oriented programming. (La registrazione, che è ciò che si desidera fare, è un'applicazione comune di AOP.) Wikipedia lists alcune implementazioni AOP per C++: AspectC++, XWeaver e FeatureC++.
+0

+1 per il suggerimento AOP! Tuttavia, leggi le preoccupazioni che ho fatto a chiunque mi suggerisca di usare un debugger e Space_C0wb0y –

+0

Decorare o creare una sottoclasse mi farebbe cambiare il codice del chiamante. Pur essendo in grado di farlo, non voglio. È meglio rendere le modifiche sul posto con define (#ifdef STATS ... #endif) che dover mettere una call di decorazione per ogni oggetto di questa classe creato. –

2

Se non ti dispiace l'inserimento di un codice a mano, è possibile creare una classe che:

  1. i registri di entrata al metodo nel costruttore
  2. fornisce un metodo per eseguire il dump dei parametri arbitrari
  3. fornisce un metodo per registrare lo stato
  4. i registri di uscita con lo stato registrato nel distruttore

L'utilizzo sarebbe simile:

unsigned long long 
factorial(unsigned long long n) { 
    Inspector inspect("factorial", __FILE__, __LINE__); 
    inspect.parameter("n", n); 
    if (n < 2) { 
     return inspect.result(1); 
    } 
    return inspect.result(n * fact(n-1)); 
} 

Naturalmente, è possibile scrivere macro per dichiarare l'ispettore e ispezionare i parametri. Se si lavora con un compilatore che supporta le macro lista degli argomenti variabili, allora si può ottenere il risultato a guardare come:

unsigned long long 
factorial(unsigned long long n) { 
    INJECT_INSPECTOR(n); 
    if (n < 2) { 
     return INSPECT_RETURN(1); 
    } 
    return INSPECT_RETURN(n * fact(n-1)); 
} 

io non sono sicuro se è possibile ottenere una soluzione più pulita senza andare a qualcosa come un AOP ambiente o qualche strumento di generazione di codice personalizzato.

+0

Bello, anche se probabilmente i vararg avranno problemi. C++ non funziona bene con le funzioni varargs, che alla fine sarà necessario utilizzare. Sono supportati, ma in realtà solo per i valori C. –

+0

Stavo pensando alla lista di argomenti variabili _macros_ per 'INJECT_INSPECTOR' sebbene non siano stati ancora ufficialmente sbrodolati in C++. Le funzioni di vararg in C++ sono decisamente da rompere per essere utilizzate in qualsiasi modo reale. Vorrei usare una chiamata separata per parametro (nome, valore) per ogni parametro, rendere la chiamata un modello e sfruttare gli iostreams per la formattazione.Sto usando qualcosa di simile in pratica oggi;) –

0

Vorrei solo utilizzare una libreria di registrazione (o alcune macro) e inserire le chiamate di registrazione manuale. A meno che la tua classe non disponga di un numero eccessivo di metodi, è probabilmente più veloce da seguire rispetto allo sviluppo e al debug di una soluzione più sofisticata.

+0

La registrazione potrebbe fare molto bene quello che sta cercando, sarà leggermente più pulito rispetto a stampare ogni riga, ma avrai una libreria aggiuntiva in sospeso (a meno che non ne abbia già una). –