Come si inseriscono gli oggetti nello stile moderno C ++ (stl, policy-classes, funzionale)?

2

Sono un po 'confuso quindi la domanda è un po' confusa. TL; dr: come mescolare STL e OOP?

Dal commento a Migliore panoramica sui paradigmi C ++ moderni? e link non c'è molto sulla programmazione orientata agli oggetti. (le linee guida di boost menzionano i generatori di oggetti).

Quando pianifichi un programma, sembra che STL e gli oggetti debbano adattarsi bene insieme. Pensi ad un algoritmo e come fare le cose, poi pensi a quali sono le cose con cui vuoi lavorare e quali proprietà / caratteristiche hanno. Esprimi queste cose in termini di tuple e contenitori e applichi loro degli algoritmi. Dalla mia comprensione, questo è lo stile di pensiero STL.

Ora è qui che entrano gli oggetti. Sono cose con cui fai roba che contengono dati, algoritmi che cambiano i dati e le interfacce. Ma questo si sovrappone all'idea di stl in cui si separano i dati e gli algoritmi.

In OO combini dati e algoritmi e in STL lo separi.

Sebbene STL matematicamente e genericamente abbia più senso (quando è possibile applicare l'algoritmo a qualsiasi cosa), è più facile pensare concettualmente in stile OO quando si hanno molti oggetti e algoritmi diversi: si ottiene un'organizzazione migliore. Ad esempio, qt-style sostiene l'uso di interfacce minime e ortogonali specifiche per una classe in opposizione al generale algoritmi. Ho detto che sono specifici perché i loro oggetti sono diversi e richiedono interfacce minime, il che significa che gli oggetti non condivideranno le stesse interfacce.

Quindi la domanda è: "puoi scappare con STL nel moderno C ++ o dovresti usare gli oggetti? E se devi usare gli oggetti, allora come?"

Altre domande pertinenti su Stack Overflow:

posta kirill_igum 21.03.2013 - 23:06
fonte

2 risposte

3

Una cosa che dovresti fare attenzione a non dimenticare è che C ++ è un linguaggio multi-paradigma. È un linguaggio che supporta le astrazioni dal codice imperativo di basso livello fino al codice funzionale di ordine superiore e quasi tutto il resto.

I contenitori standard (non la STL - che è una libreria per lo più non correlata ) sono un tipo di astrazione che si trova più vicino alla parte funzionale dello spettro del paradigma. Fornisce l'interfaccia più generica possibile per una categoria di algoritmi standard, in una forma che segue uno stile funzionale, uno stile in cui gli algoritmi e le strutture dati sono descritti in termini molto elevati ma coerenti.

Questo non è in contrasto con il paradigma orientato agli oggetti a cui sei abituato. Piuttosto, è sia ortogonale che complementare.

Il motivo per cui le moderne discussioni in C ++ non ruotano molto attorno all'orientamento agli oggetti è semplicemente dovuto al fatto che gli oggetti sono solo uno dei tanti strumenti che il C ++ offre per modellare i calcoli che sono alla base dei tipi definiti dall'utente.

Per ribadirlo in un altro modo: l'attenzione nel moderno C ++ è in tipi . Gli oggetti capita di essere utilizzati per modellare il comportamento di alcuni tipi e modelli e funzioni modellano il comportamento di altri tipi.

Questo non è il "modo di pensare STL", piuttosto, è un paradigma che sfrutta appieno il paradigma funzionale in questo modo in cui C ++ può supportarlo.

Quando si pianifica un programma, si determinano i comportamenti principali e la sovrastruttura del modello dati. Quindi, si costruisce un modello di calcolo che incorpora sia i comportamenti che il modello di dati. In effetti, dovresti pensare prima al modello di dati, quindi agli algoritmi per operare su di esso.

La libreria standard fornisce le strutture e gli algoritmi di dati lineari più comunemente usati che li mutano. Le liste di vario tipo sono il modello più conveniente e più facile da modellare delle principali strutture di dati, e il paradigma funzionale ci insegna che gli algoritmi più convenienti per quelle strutture dati sono quelli che la libreria standard ha scelto di fornire. Il resto del C ++ (classi, ereditarietà, funzioni, modelli, ecc.) Fornisce un modo efficace per modellare efficientemente tali strutture dati e algoritmi, senza sacrificare la loro genericità.

Il modo in cui scegli di implementare le tue strutture dati e gli algoritmi non ha importanza per C ++: ti fornisce tutti gli strumenti necessari per modellare i calcoli in qualsiasi forma tu ritenga conveniente. Ma quella larghezza espressiva arriva al costo della complessità. Alcuni modelli che potresti scegliere potrebbero non essere sicuri per il tipo. C ++ ti permette di usarli, ma fornisce anche modelli di tipo sicuro e generico.

La tua domanda è, penso, quella sbagliata.

La domanda che dovresti porre non è "dovrei usare i contenitori standard o usare gli oggetti", ma piuttosto "Quale classe di algoritmi e strutture dati modella più chiaramente il mio programma?"

Se hai bisogno di una semplice struttura dati e le operazioni primarie su quella struttura dati sono strettamente modellate dalla libreria degli algoritmi standard, la usi in ogni caso. Fanno parte della libreria standard perché sono pensati per essere utili. È completo, in quanto fornisce tutte le astrazioni di alto livello che il tuo programma avrà mai bisogno, ma potrebbe non sempre farlo in un modo che rende chiaro il tuo codice. Questo è il motivo per cui C ++ fornisce tutti i suoi altri strumenti: per darti un modo di modellare i tuoi tipi di astrazione.

    
risposta data 22.03.2013 - 18:52
fonte
1

Vengo da uno sfondo in cui sono state acquisite la maggior parte delle mie competenze OO utilizzando C #. Tuttavia, la maggior parte delle mie competenze di programmazione generiche provengono dal C ++. Recentemente ho scritto un C ++ progetto che ha cercato ricorsivamente i siti web per alcune cose (un web spider). Ho costantemente incontrato problemi ogni volta che ho provato a mixare OO e STL.

Gli oggetti non amano esporre i loro interni. Quelli interni sono le strutture di dati (vettori, mappe, ecc.) Con cui altri oggetti vogliono interagire. È sempre stato maldestro creare metodi di accesso / mutatore per queste strutture dati. I consumatori delle mie classi non potevano usare l'STL per afferrare e manipolare i miei dati come meglio credevano.

È molto facile usare l'STL entro i confini di una classe. Hai tutto ciò di cui hai bisogno. Ma quando inizi a interagire con altri oggetti, usare l'STL è difficile senza violare l'incapsulamento. Uno degli argomenti su cui ho fatto ricerche consisteva in generici iteratori (iteratori che non espongono il tipo di raccolta sottostante). Anche con iteratori generici, il tuo consumatore deve sapere se l'iteratore è ad accesso casuale, avanti, bidirezionale, ecc.

Un altro approccio che ho adottato in seguito è stato il passaggio di funzioni ai membri. Un oggetto passerebbe un funtore alla funzione membro di un altro oggetto che lo inoltrerebbe a un algoritmo STL. A volte dovrei decorare / adattare il functor per non esporre dettagli di implementazione su come i dati sono stati archiviati internamente. Il problema con questo approccio era che divenne difficile sapere chi "possedeva" un pezzo di funzionalità. Inoltre, significava che queste funzioni membro erano modelli, che limitavano dove potevo definire le loro implementazioni. Molti dei problemi che ho incontrato con le funzioni dei membri del template andranno via con C ++ 11.

Ho finito per creare classi che ritenevo fossero molto esposte o le cui implementazioni erano distribuite su troppe altre classi. Molto di questo è venuto dal mio desiderio di evitare di scrivere cicli espliciti ed evitare inefficienze. Credo in un progetto professionale che probabilmente limiterei il mio utilizzo della STL all'interno dei confini delle mie classi. Ho speso modo troppo tempo cercando di usare l'STL ovunque potessi.

Ormai dovrebbe essere ovvio che probabilmente non sono la persona migliore per dare consigli. Volevo solo condividere con te che i due stili non sono sempre facili da combinare. Il libro di Bjarne Stroustrup Il linguaggio di programmazione C ++ sottolinea come il linguaggio C ++ sia stato progettato per consentire ai programmatori di passare da un paradigma all'altro secondo necessità. Non penso che intendesse il linguaggio per rendere più facile combinarli necessariamente. La maggior parte dei suoi esempi riguardanti OOP toccano molto poco l'STL. Crea strati molto distinti.

Consiglierei di dare un'occhiata al mio progetto per vedere come ho usato l'STL attraverso i limiti dell'oggetto. Come ho detto, non è perfetto ma fornirà alcuni esempi che potrebbero essere utili.

    
risposta data 22.03.2013 - 17:39
fonte

Leggi altre domande sui tag