Posso sovraccaricare l'operatore [] []?

3

Sto scrivendo un tipo Matrix , e vorrei il seguente codice per definire una matrice di 2,2 in%, mettere il suo primo elemento a 3 e lanciare un'eccezione al raggiungimento della terza riga:

Matrix<int> a(2,2);
a[0][0] = 3;
int b = a[10][28];

Per questo, ho bisogno di sovraccaricare " operator[][] ". Lasciatemi spiegare ulteriormente:

  • La mia matrice è definita come un modello con tipo di parametro T e memorizza i suoi elementi in un array bidimensionale definito come T** content .
  • Il mio punto di sovraccarico " operator[][] " è di evitare una violazione di accesso e generare un'eccezione che può essere gestita in seguito (una violazione di accesso è not un'eccezione).
  • Sovraccaricare operator[] una volta mi avrebbe permesso di usare a[0] e a[0] restituirebbe un tipo T* .
  • Per sovraccaricare il " operator[][] " di Matrix , in realtà ho bisogno di sovraccaricare il operator[] del mio sopramenzionato T* di tipo restituito.
  • Poiché T* è un array, il suo operator[] è già definito e funziona bene, quindi non c'è motivo di cambiarlo.
  • Anche se l'ho fatto, non potrei fare nulla di rilevante per il mio punto perché è al di fuori della classe Matrix .

Come posso risolvere questo problema?
Potrei fare il primo sovraccarico operator[] restituire un nuovo oggetto MatrixRow con cui posso lavorare ulteriormente, ma non è una soluzione piuttosto pesante?

    
posta qreon 09.12.2016 - 02:13
fonte

1 risposta

5

Non c'è operator[][] in C ++. Quando si utilizzano indici multidimensionali, operator[] viene applicato in sequenza al risultato del precedente.

Esempio: a[i][j] applica operator[](i) a a . Quindi applica operator[](j) al risultato.

Ora ci sono almeno 4 modi per risolvere il tuo problema:

  • overload operator[]() con un oggetto che combina entrambe le coordinate, ad esempio comprimendole in una coppia con operator[] (pair<size_t, size_t>) . Questo è bello in teoria, ma rende l'indicizzazione goffa.
  • overload operator[] per restituire un riferimento a un oggetto che rappresenta la riga (ad esempio MatrixRow ) e con se stesso ha un operator[] appropriato. Questo è un approccio molto pulito. Tuttavia, richiede che Matrix sia un aggregato di MatrixRow (perché è necessario essere in grado di restituire un riferimento ad esso). Sfortunatamente, questo è ora sempre possibile (ad esempio, alcune strutture di matrice sparse usano schemi di compressione che non consentono un oggetto riga indirizzabile direttamente).
    Aggiornamento: Una variante di questo approccio potrebbe essere quella di restituire un oggetto proxy per la riga anziché un riferimento. Questo è un po 'più complicato perché il proxy deve emulare il comportamento di un riferimento di riga (vedere la discussione nei commenti) e ha ancora bisogno di una classe per rappresentare una riga matrice completa per questo scopo. Tuttavia, la complessità aggiuntiva presenta il vantaggio di disaccoppiare la rappresentazione interna della matrice dalla rappresentazione di una riga intera. (Grazie Angew per questo suggerimento)
  • mostra i dettagli interni dell'implementazione, restituendo direttamente il puntatore all'array. Mentre questo è molto comodo, non è davvero un progetto pulito, perché si crea una dipendenza del codice usando i dettagli interni di Matrix.
  • overload operator() , che consente più parametri. Il problema principale qui è quello di essere abituati all'uso di () invece di [] . Se andate per questo, è meglio non definire un operatore [] per Matrix, solo per evitare alcuni sottili errori che potrebbero sorgere quando si combina accidentalmente [] con l'uso dell'operatore di coma.

Una domanda però: perché usi ancora gli array, quando invece puoi usare più efficacemente i vettori?

Esempio dell'ultimo approccio:

template <class T>
class Matrix {
    vector<vector<T>> m; 
public: 
    Matrix (int r, int c) : m(r, vector<int>(c, T())) { }
    T& operator() (int r, int c) { return m[r][c]; }
    ...
};

Matrix a(2,2); 
a(1,0) = 5;
int e = a(1,0);

Per ulteriori esempi (utilizzando 3 dei 4 approcci discussi), vedi demo online .

    
risposta data 12.12.2016 - 00:25
fonte

Leggi altre domande sui tag