Operatori di Accesso ai Membri in C++

Concetti Chiave
  • Gli operatori di accesso ai membri in C++ forniscono un modo per accedere ai membri di una classe o struttura.
  • L'operatore punto (.) viene utilizzato per accedere ai membri di un oggetto.
  • L'operatore freccia (->) viene utilizzato per accedere ai membri di un oggetto tramite un puntatore.
  • La dereferenziazione di un puntatore ha una precedenza inferiore rispetto all'operatore punto.
  • L'operatore freccia richiede un operando puntatore e produce un l-value.
  • L'operatore punto produce un l-value se l'oggetto da cui viene recuperato il membro è un l-value; altrimenti il risultato è un r-value.

Gli Operatori di Accesso ai Membri

Gli operatori punto . e freccia -> forniscono l'accesso ai membri di una struttura o classe. L'operatore punto recupera un membro da un oggetto di tipo classe; la freccia è definita in modo tale che ptr->membro sia un sinonimo di (*ptr).membro:

string s1 = "a string", *p = &s1;

// Invoca la funzione membro (metodo) della string s1
auto n = s1.size();

// Invoca la funzione membro (metodo) dell'oggetto a cui p punta
n = (*p).size();

// equivalente a (*p).size()
n = p->size();

Poiché la dereferenziazione ha una precedenza inferiore rispetto al punto, dobbiamo mettere tra parentesi la sottoespressione di dereferenziazione. Se omettiamo le parentesi, questo codice significa qualcosa di molto diverso:

// esegue il membro size di p, poi dereferenzia il risultato!
// ERRORE: p è un puntatore e non ha un membro chiamato size
*p.size();

Questa espressione tenta di recuperare il membro size dell'oggetto p. Tuttavia, p è un puntatore, che non ha membri; questo codice non compilerà.

L'operatore freccia richiede un operando puntatore e produce un l-value. L'operatore punto produce un l-value se l'oggetto da cui viene recuperato il membro è un l-value; altrimenti il risultato è un r-value.

Esercizi

  • Assumendo che iter sia un vector<string>::iterator, indica quali, se ce ne sono, delle seguenti espressioni sono legali. Spiega il comportamento delle espressioni legali e perché quelle che non sono legali sono in errore.

    *iter++;
    

    Soluzione: Questa espressione è legale. L'operatore di post-incremento ++ ha una precedenza più alta rispetto all'operatore di dereferenziazione *. Quindi, l'espressione viene interpretata come *(iter++). Questo significa che l'iteratore iter viene incrementato ma una sua copia (il valore prima dell'incremento) viene passata all'operatore di dereferenziazione. In altre parole, l'operatore * restituisce l'elemento corrente a cui iter puntava prima dell'incremento, ma iter stesso viene spostato al prossimo elemento.

    (*iter)++;
    

    Soluzione: Questa espressione non è legale perché tenta di incrementare un oggetto di tipo string. L'operatore di post-incremento ++ non è definito per il tipo string, quindi questa espressione causerà un errore di compilazione.

    *iter.empty();
    

    Soluzione: Questa espressione non è legale. L'operatore di dereferenziazione * ha una precedenza più bassa rispetto all'operatore di accesso ai membri .. Quindi, l'espressione viene interpretata come *(iter.empty()). Tuttavia, iter è un iteratore e non ha un membro chiamato empty(). Questo causerà un errore di compilazione.

    iter->empty();
    

    Soluzione: Questa espressione è legale. L'operatore di accesso ai membri -> viene utilizzato per accedere al membro empty() della stringa a cui iter punta. La funzione empty() restituisce un valore booleano che indica se la stringa è vuota o meno.

    ++*iter;
    

    Soluzione: Questa espressione non è legale perché tenta di incrementare un oggetto di tipo string. L'operatore di pre-incremento ++ non è definito per il tipo string, quindi questa espressione causerà un errore di compilazione.

    iter++->empty();
    

    Soluzione: Questa espressione è legale. Qui, l'operatore di post-incremento ++ viene applicato a iter, che è un iteratore. L'operatore -> viene quindi utilizzato per accedere al membro empty() della stringa a cui iter puntava prima dell'incremento. La funzione empty() restituisce un valore booleano che indica se la stringa è vuota o meno.