La modifica del membro privato di una classe tramite un operatore di pedice sovraccarico interrompe l'incapsulamento?

1

Mi è sempre stato insegnato che per mantenere gli incapsulamenti gli oggetti dovrebbero essere responsabili di eseguire calcoli sui propri dati.

Quindi, in questo caso, ecco le regole di rottura dell'incapsulamento e considerate pratiche sbagliate?

#include <iostream>
using namespace std;
const int SIZE = 10;

class safearay {
private:
    int arr[SIZE];
public:
    safearay() {
        register int i;
        for (i = 0; i < SIZE; i++) {
            arr[i] = i;
        }
    }

    int &operator[](int i) {
        if (i > SIZE) {
            cout << "Index out of bounds" << endl;
            // return first element.
            return arr[0];
        }
        return arr[i];
    }
};

int main() {
    safearay A;

    cout << "Value of A[2] : " << A[2] << endl;
    cout << "Value of A[5] : " << A[5] << endl;
    cout << "Value of A[12] : " << A[12] << endl;
    A[5] = 2; // Does this break Encapsulation?? 
    cout << "Value of A[5] : " << A[5] << endl;
    return 0;
}
    
posta ohkneel 07.02.2017 - 09:47
fonte

2 risposte

2

L'obiettivo dell'incapsulamento è prevenire modifiche arbitrarie dei dati. Il modo più comune per ottenere questo in C ++ consiste nel mettere i dati nella sezione privata di una classe e solo mettendo un insieme limitato di metodi che possono modificare tali dati nella sezione pubblica. Ogni metodo pubblico indica all'utente cosa può essere fatto ai dati. Le implementazioni di questi metodi hanno la responsabilità di preservare lo stato valido dei dati.

Nella tua classe, operator[] consente di modificare qualsiasi elemento dell'array. Se l'utente dovrebbe essere autorizzato a farlo, allora va bene. È una tua decisione ciò che l'utente è autorizzato a fare. Fornisci anche una protezione per assicurarti che l'indice fornito dall'utente sia entro i limiti. Questa è una buona cosa. Questo tipo di controllo è simile al metodo std::vector::at() .

Alcuni metodi sono più difficili da giustificare:

class Foo
{
    private:
        int x;
    public:
        int& my_x() { return x; }
}

Con questa classe, l'esistenza del metodo my_x() equivale esattamente a rendere int x pubblico. Questo rappresenta quasi sempre l'incapsulamento rotto. Potrebbe essere necessario, a volte. Mi viene in mente il metodo std::shared_ptr::get() , che espone il puntatore che shared_ptr sta custodendo. A volte, tuttavia, l'utente ha legittimamente bisogno di questo tipo di accesso. Ecco perché la risposta universale a tutte le domande di ingegneria è "Dipende".

I problemi con la classe sono misure di sicurezza inadeguate nel controllo dell'indice dell'array. L'utente non viene informato quando l'indice i è negativo. Inoltre, la stampa su cout non è un avvertimento abbastanza strong per l'utente. Inoltre, restituire un elemento casuale dell'array quando l'indice è fuori limite è un comportamento ostile all'utente. Dico casuale perché arr[0] non è i dati richiesti dall'utente. Lanciare un'eccezione sarebbe un'azione migliore per costringere l'utente a controllare il proprio codice per ottenere l'indice giusto.

    
risposta data 14.02.2017 - 05:59
fonte
1

Stai rompendo l'incapsulamento in modo cattivo.

Restituendo un riferimento a un elemento dell'array, hai perso il controllo su quell'elemento dell'array per sempre. Chiamo

int* p = &A [5];

e ora posso sempre e in qualsiasi momento cambiare il valore della tua variabile privata arr [5] (e in realtà anche gli altri elementi, scrivendo p [-5] = p [4] = 0.

Se si desidera esporre l'array, esporre l'array. Ma hai provato a nasconderlo, e non l'hai fatto.

    
risposta data 14.02.2017 - 14:24
fonte

Leggi altre domande sui tag