Funzioni membro vs Funzioni non membro per gli operatori matematici


12

Sto scrivendo una libreria di algebra lineare (per farla breve, è un compito scolastico) che coinvolge matrici, vettori, ecc. Nel processo di creazione di questa libreria, creerò funzioni che eseguono operazioni matematiche sugli oggetti. Ad esempio, trasponi matrice, inverti matrice, normalizza vettore, ecc.

Ero curioso di sapere qual è la "migliore pratica" per questo tipo di funzione ... Cioè, dovrei rendere la funzione una funzione membro o non membro? (Per chiarezza / uso della biblioteca)

Esempio:

//Member function way:
B = A.transpose();
C = A.inverse();

//Non-member function way:
B = linalg::transpose(A); //Non-member transpose function in linear algebra namespace
C = linalg::inverse(A);

Esistono standard relativi a questo tipo di operazioni? O almeno c'è un modo comune in cui le persone lo fanno? Mi sto inclinando verso la prima opzione, ma vorrei sapere se questo è raccomandato.

Risposte:


7

Questa è solo una questione di stile e gusto. Ho visto anche diverse librerie di algebra lineare

  • scritto in uno stile OOP usando le funzioni membro

  • scritto in uno stile non OOP usando solo funzioni gratuite

  • fornendo un'API con entrambi

e tutti stavano lavorando. Almeno, l'API dovrebbe essere coerente, quindi scegli la tua scelta e assicurati di non mescolare quegli stili in modo arbitrario.


8

Evita le quote associative: ove possibile, preferisci rendere le funzioni non amichevoli.

Le funzioni non amichevoli non membro migliorano l'incapsulamento minimizzando le dipendenze: il corpo della funzione non può dipendere dai membri non pubblici della classe (vedi Articolo 11). Inoltre, suddividono le classi monolitiche per liberare la funzionalità separabile, riducendo ulteriormente l'accoppiamento (vedi Articolo 33). Migliorano la genericità, perché è difficile scrivere modelli che non sanno se un'operazione è o meno un membro per un determinato tipo [...]

Herb Sutter


1
Finalmente una buona risposta: tardi, ma non troppo tardi. ;-) Un altro riferimento: GotW # 84: Monoliths "Unstrung"
Deduplicator

1

Entrambe le funzioni membro e non membro presentano vantaggi reali oltre al semplice gusto. Ad esempio, gli array sottostanti utilizzati per implementare una matrixclasse saranno probabilmente private, pertanto, sarà necessario utilizzare a friendmeno che non si utilizzino le funzioni membro. A questo proposito, un design OO potrebbe essere migliore.

Tuttavia, tieni presente che, di tanto in tanto, gli informatici devono implementare una formula matematica complessa senza sapere sempre cosa fai veramente. Quando devo farlo, preferisco le funzioni non membro poiché il risultato "visivo" sarà più vicino alla formula matematica originale (poiché la formula matematica generalmente usa uno stile funzionale).

Alla fine, la risposta è la stessa di Doc Brown: è una questione di gusti. In breve, potresti considerare di scrivere una libreria in stile OO con funzioni membro (più facile da scrivere, no friend), quindi scrivere funzioni non membro per fare le stesse attività che semplicemente inoltreranno i loro argomenti a quelle membri. Ti consente di essere coerente e di consentire all'utente di scegliere ciò che ritiene migliore.


0

Se ti immergi più a fondo nell'affermazione del problema, è chiaro che ad un certo punto utilizzerai strutture di dati personalizzate che rappresentano determinate entità matematiche. Ad esempio, potresti rappresentare una matrice per mezzo di una matrice n-dimensionale. Per elaborare il tuo esempio,

// C way
typedef struct {
    int data[MAX_LEN][MAX_LEN];
} MATRIX;

MATRIX B = transpose(A);

// C++ way
class Matrix; // Forward Declaration
class Matrix {
    int data[MAX_LEN][MAX_LEN];
    public:
        Matrix transpose();
};

Matrix B = A.transpose();

(L'esempio C ++ è semplificato, è possibile utilizzare modelli e simili.)

Il punto da considerare è la facilità di utilizzo delle strutture di dati personalizzate in entrambi i casi. Il C ++ (o qualsiasi oggetto orientato) come linguaggio è più potente in sé e ciò si estende al consumatore della libreria tanto quanto avvantaggia l'implementatore. Ho usato solo librerie C in passato e quelle strutture di dati personalizzate sembrano andare ovunque in pochissimo tempo! Considerando che l'interoperabilità è più facile da raggiungere con quest'ultima (usando costruttori speciali, forse?)

Per concludere, se stai usando C ++ allora è decisamente raccomandato un approccio orientato agli oggetti.


5
Ci dispiace, ci sono pochi fatti concreti nel tuo ragionamento. Non c'è differenza nella facilità d'uso tra i tuoi due transposeesempi. Il motivo principale per cui C ++ è più semplice è perché la semantica di copia e assegnazione funziona davvero. A = Bpuò compilare in C ma probabilmente fa la cosa sbagliata.
MSalters il

+1 per la semantica della copia Il punto che stavo cercando di ottenere è usare oggetti (incapsulamenti su "rappresentazioni") v / s usando un set di strutture liberamente accoppiate e funzioni correlate.
dotbugfix
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.