Esiste una diversa logica di utilizzo per le classi / interfacce astratte in C ++ e Java

13

Secondo Herb Sutter uno dovrebbe preferire le interfacce astratte (tutte le funzioni pure virtuali) alle classi astratte in C ++ per disaccoppiare l'implementazione il più lontano possibile. Mentre personalmente trovo questa regola molto utile, ho recentemente raggiunto un team con molti programmatori Java e nel codice Java questa linea guida non sembra esistere. Le funzioni e le loro implementazioni sono localizzate molto frequentemente in classi astratte. Così ho sbagliato Herb Sutter anche per C ++ o c'è una differenza generale nell'uso delle funzioni astratte in C ++ rispetto a Java. Le classi astratte con codice di implementazione sono più sensate in Java che in C ++ e se sì perché?

    
posta Martin 07.08.2012 - 22:48
fonte

4 risposte

5

OOP ha composizione e sostituzione.

C ++ ha una molteplicità di ereditarietà, specializzazione template, incorporamento e valore / spostamento / puntatore semantica.

Java ha un'unica ereditarietà e interfacce, incorporamento e semantica di riferimento.

Il modo comune con cui la scuola OOP usa questi linguaggi è di utilizzare l'ereditarietà per la sostituzione di oggetti e l'incorporamento per la composizione. Ma hai anche bisogno di un antenato comune e un modo per eseguire il cast in runtime (in C ++ si chiama dynamic_cast , in Java stai solo chiedendo un'interfaccia da un altro).

Java fa tutto questo con la sua stessa gerarchia di root java.lang.Object . C ++ non ha una root comune predefinita, quindi dovresti almeno definirla, per arrivare ad una stessa "immagine" (ma questo limita alcune possibilità del C ++ ...).

Dopo di ciò, la possibilità di avere il polimorfismo in fase di compilazione (si pensi al CRTP) e il valore semantico possono offrire anche altre alternative al modo in cui il concetto di "oggetto OOP" può essere trasferito in un programma C ++.

Si può anche immaginare l'eresia di utilizzare l'incorporamento e la conversione implicita per gestire la sostituzione e l'ereditarietà privata per gestire la composizione, invertendo di fatto il paradigma scolastico tradizionale. (Ovviamente, in questo modo è 20 anni più giovane dell'altro, quindi non aspettarti un ampio supporto da parte della comunità nel farlo)

Oppure puoi immaginare una base comune virtuale per tutte le classi, l'interfaccia del modulo (nessuna implementazione) alle classi finali (completamente implementate) passando attraverso interfacce parzialmente implementate e un cluster di interfaccia uniforme, usando "dominanza" come dispacciamento dall'interfaccia alle implementazioni attraverso un schema di ereditarietà "multi stacked-parallelogram".

Confrontando OOP con java con C ++ supponendo che ci sia solo un solo modo OOP sta limitando le capacità di entrambe le lingue.

Forzare C ++ a rispettare rigorosamente gli idiomi di codifica Java è denaturare C ++ come forzare Java a comportarsi come un linguaggio C ++ come la denaturazione di Java.

Non è una questione di "sensibilità" ma di diversi "meccanismi di aggregazione" che le due lingue hanno e un modo diverso di combinarle che rende alcuni idiomi più proficui in una lingua rispetto all'altra e viceversa.

    
risposta data 08.08.2012 - 21:59
fonte
12

Il principio vale per entrambe le lingue, ma non stai facendo un confronto equo. È necessario confrontare le classi astratte pure C ++ con le interfacce Java.

Anche in C ++, puoi avere classi astratte che hanno alcune delle funzioni implementate, ma derivano da una pura classe astratta (senza implementazioni). In Java, avresti le stesse classi astratte (con alcune implementazioni), che possono derivare da interfacce (senza implementazioni).

    
risposta data 07.08.2012 - 22:52
fonte
4

Generalmente gli stessi principi OO valgono per Java e C ++. Tuttavia, una grande differenza è che C ++ supporta l'ereditarietà multipla mentre in Java è possibile ereditare solo da una classe. Questo è il motivo principale per cui Java ha interfacce che io credo, da integrare per la mancanza di ereditarietà multipla e probabilmente per limitare ciò che si può fare con esso (dal momento che ci sono molte critiche sull'abuso dell'eredità multipla). Quindi, probabilmente in una mente di programmatori Java, c'è una distinzione più strong tra classi astratte e interfacce. Le classi astratte vengono utilizzate per condividere ed ereditare il comportamento mentre le interfacce vengono semplicemente utilizzate per aggiungere funzionalità aggiuntive. Ricorda, in Java puoi ereditare da una sola classe, ma puoi avere molte interfacce. In C ++, tuttavia, le classi astratte pure (cioè una "interfaccia C ++") sono utilizzate per condividere ed ereditare comportamenti diversi dallo scopo di un'interfaccia Java (sebbene sia ancora necessario implementare le funzioni), da qui il l'utilizzo è diverso dalle interfacce Java.

    
risposta data 07.08.2012 - 23:50
fonte
0

A volte ha senso avere alcune implementazioni predefinite. Ad esempio un metodo generico PrintError (string msg) applicabile a tutte le sottoclassi.

virtual PrintError(string msg) { cout << msg; }

Può ancora essere sovrascritto se richiesto, ma è possibile salvare il client alcune seccature consentendogli di chiamare semplicemente la versione generica.

    
risposta data 07.08.2012 - 23:20
fonte

Leggi altre domande sui tag