Qual è la corretta relazione OOP tra numeri complessi e numeri reali?

3

Da un lato

class complex {
    double real;
    double imaginary;
}

è composizione

d'altraparte

classcomplex:double{doubleimaginary;}

èereditarietà

Quale è corretto? Perché le frecce vanno nella direzione opposta, denotando la stessa cosa? Chi ha inventato tutto questo?

    
posta Dims 22.04.2016 - 13:00
fonte

5 risposte

2

L'indicatore di associazione non è una freccia, è una relazione binaria contrassegnata su un lato (in modo da poter distinguere la coda del cane da quella di coda-cane). E la freccia dell'eredità sembra che si stia "muovendo" in una direzione particolare, ma non vi è alcun motivo particolare per cui qualsiasi cosa verrebbe spostata dalla superclasse alla sottoclasse o dalla sottoclasse della superclasse. Di nuovo, è solo un modo per marcare la relazione asimmetrica, che è necessaria perché la differenza tra "A is-a B" e "B is-a A" è importante.

Più in generale, queste notazioni sono in gran parte arbitrarie nello stesso modo in cui scrivere "A" per un suono vocale particolare e "B" per una particolare consonante è arbitrario: nessuno di questi segni ha alcuno speciale affinità per la cosa che denotano, e potremmo anche aver scelto simboli diversi. La cosa importante è che ora tutti sono d'accordo come scrivere i suoni.

Allo stesso modo, in OOP siamo ora ampiamente d'accordo su come disegnare un diagramma di classe, e questo ci permette di comunicare in modo più efficiente, anche quando i dispositivi che usiamo per la notazione non sono particolarmente convincenti. Chiedendosi perché un tipo di freccia rappresenta una cosa e un altro tipo per un'altra cosa non può che insegnarti la storia di UML, non in realtà sullo sviluppo del software, quindi è quasi sbagliato.

    
risposta data 22.04.2016 - 13:09
fonte
2

Problemi grafici (ical) a parte, il caso dell'eredità mi sembra sbagliato. Un numero complesso è composto da due membri dati e non vedo alcun vantaggio nell'integrarne uno e nell'aggiungere l'altro. Ancora peggio, potresti essere in grado di eseguire calcoli non validi con un numero complesso e non complesso (doppio o intero) quando deriva dal doppio, mentre penso che queste operazioni debbano essere racchiuse nei metodi quando sono valide. Usando la composizione il compilatore si rifiuterà di farlo, finché non sovraccarichi un operatore con l'implementazione (si spera corretta).

"Esplicito è meglio di implicito."

    
risposta data 22.04.2016 - 13:30
fonte
1

Per citare Eric Evans, "un modello non è né giusto né sbagliato, solo più o meno utile"

Una gerarchia di ereditarietà può essere utile se si ha realmente bisogno di operare su molti tipi diversi di numeri ed essere in grado di gestirli in modo astratto. In questo caso forse hai anche bisogno della classe Fraction , e forse la classe base astratta non è né Complex , né double ma a Number class. Un Complex consisterebbe ovviamente in due istanze Number . Tutti gli operatori matematici prenderebbero i numeri come input e restituiranno le istanze del numero, ma il tipo di ritorno effettivo dipenderà dai tipi di input. Dividi due double s e ottieni double . Dividi due integer s e ottieni Fraction . Moltiplica una frazione per il suo denominatore e ottieni un intero.

Ma non ho mai lavorato con un'applicazione in cui tale astrazione sia utile. Se stai operando su numeri complessi, le funzioni che richiedono numeri complessi sanno che hanno bisogno di numeri complessi, non di un'astrazione di base.

L'overloading dell'operatore sarebbe probabilmente utile (se il linguaggio lo supporta), consentendo di aggiungere o moltiplicare facilmente numeri complessi e in virgola mobile. Ma essere in grado di operare su di essi in modo astratto è raramente necessario.

    
risposta data 22.04.2016 - 14:03
fonte
0

Perché non rendere reale un caso speciale di complesso in cui l'immaginario sembra essere 0. Questo obbedisce al principio di sostituzione che afferma che una sottoclasse deve sempre essere in grado di sostituire la superclasse. Ciò significa che real dovrebbe ereditare da complex (perché un numero reale è un numero complesso ).

In ogni caso non mi preoccuperei troppo di questo e mi assicuro che potrei convertire da complesso a reale.

    
risposta data 22.04.2016 - 13:42
fonte
0

Sfortunatamente, è difficile modellare le relazioni tra tipi numerici usando il tipico set di funzioni di un linguaggio orientato agli oggetti. Puoi avvicinarti modellando sia reali che complesse come istanze di un "numero" di interfaccia, ma la semantica OO ti farà inciampare perché in molti casi le funzioni dei valori reali vorranno ritornare reali e le stesse funzioni vorranno restituire complesse per complesse argomenti. Dovrai scendere a compromessi e solo restituire i numeri senza specificare quale, ma questo finisce con una perdita di informazioni sul tipo (almeno per le lingue statiche), che potrebbe essere indesiderabile.

Una risposta migliore è l'uso di funzioni polimorfiche, piuttosto che di classi, insieme a qualche tipo di sistema di vincoli per garantire che gli argomenti del tipo siano tipi numerici appropriati. Questo è il modo in cui molti linguaggi funzionali gestiscono il problema, e se c ++ ottiene il sistema di restrizione del concetto di modello Il comitato di c ++ ha lavorato per anni, saresti in grado di ottenere un risultato simile in c ++. In caso contrario, il sovraccarico ad hoc è probabilmente il migliore che si possa ottenere.

    
risposta data 22.04.2016 - 19:45
fonte

Leggi altre domande sui tag