Domanda

Dovresti mai usare variabili membro protette?Quali sono i vantaggi e quali problemi può comportare?

È stato utile?

Soluzione

Dovresti mai usare variabili membro protette?

Dipende da quanto sei esigente riguardo allo stato nascosto.

  • Se non vuoi alcuna perdita di stato interno, dichiarare private tutte le variabili membro è la strada da percorrere.
  • Se non ti interessa veramente che le sottoclassi possano accedere allo stato interno, allora protected è abbastanza buono.

Se arriva uno sviluppatore e crea sottoclassi la tua classe, potrebbe rovinarla perché non la capisce appieno.Con i membri privati, oltre all'interfaccia pubblica, non possono vedere i dettagli specifici dell'implementazione di come vengono eseguite le cose, il che ti dà la flessibilità di modificarlo in seguito.

Altri suggerimenti

La sensazione generale oggigiorno è che essi causino un indebito accoppiamento tra le classi derivate e le loro basi.

Non hanno alcun vantaggio particolare rispetto ai metodi/proprietà protetti (una volta potevano avere un leggero vantaggio in termini di prestazioni) e venivano anche utilizzati di più in un'epoca in cui era di moda l'ereditarietà molto profonda, cosa che non è al momento.

In genere, se qualcosa non è concepito deliberatamente come pubblico, lo rendo privato.

Se si verifica una situazione in cui ho bisogno di accedere a quella variabile o metodo privato da una classe derivata, lo cambio da privato a protetto.

Questo non accade quasi mai: non sono affatto un fan dell'ereditarietà, poiché non è un modo particolarmente buono per modellare la maggior parte delle situazioni.In ogni caso, vai avanti, non preoccuparti.

Direi che questo va bene (e probabilmente il modo migliore per farlo) per la maggior parte degli sviluppatori.

Il semplice fatto della questione è, se qualche altro sviluppatore arriva un anno dopo e decide di aver bisogno dell'accesso alla tua variabile membro privata, modificherà semplicemente il codice, lo cambierà in protetto e porterà avanti la propria attività.

Le uniche vere eccezioni a questo sono se ti occupi della spedizione di DLL binarie in forma di scatola nera a terzi.Questo è costituito fondamentalmente da Microsoft, dai fornitori di "Custom DataGrid Control" e forse da alcune altre app di grandi dimensioni fornite con librerie di estensibilità.A meno che tu non rientri in quella categoria, non vale la pena spendere tempo/sforzi per preoccuparsi di questo genere di cose.

In generale, manterrei le variabili membro protette nel raro caso in cui si abbia il controllo totale anche sul codice che le utilizza.Se stai creando un'API pubblica, direi mai.Di seguito, faremo riferimento alla variabile membro come a una "proprietà" dell'oggetto.

Ecco qual è la tua superclasse non può fare dopo aver reso protetta una variabile membro anziché privata con accessori:

  1. creare pigramente un valore al volo quando la proprietà viene letta.Se aggiungi un metodo getter protetto, puoi creare pigramente il valore e restituirlo.

  2. sapere quando la proprietà è stata modificata o cancellata.Ciò può introdurre bug quando la superclasse fa ipotesi sullo stato di quella variabile.Creare un metodo setter protetto per la variabile mantiene quel controllo.

  3. Imposta un punto di interruzione o aggiungi un output di debug quando la variabile viene letta o scritta.

  4. Rinominare la variabile membro senza cercare in tutto il codice che potrebbe utilizzarla.

In generale, penso che sarebbe il raro caso in cui consiglierei di creare una variabile membro protetta.È meglio dedicare qualche minuto a esporre la proprietà tramite getter/setter piuttosto che ore dopo rintracciare un bug in qualche altro codice che ha modificato la variabile protetta.Non solo, ma sei assicurato contro l'aggiunta di funzionalità future (come il caricamento lento) senza violare il codice dipendente.È più difficile farlo dopo che farlo adesso.

A livello di progettazione potrebbe essere appropriato utilizzare una proprietà protetta, ma per l'implementazione non vedo alcun vantaggio nel mapparla su una variabile membro protetta anziché su metodi di accesso/mutatore.

Le variabili membro protette presentano svantaggi significativi perché consentono effettivamente al codice client (la sottoclasse) di accedere allo stato interno della classe base class.Ciò impedisce alla classe base di mantenere effettivamente i propri invarianti.

Per lo stesso motivo, le variabili membro protette rendono anche molto più difficile la scrittura di codice multi-thread sicuro, a meno che non sia garantito costante o limitato a un singolo thread.

I metodi di accesso/mutatore offrono stabilità API notevolmente maggiore e flessibilità di implementazione in fase di manutenzione.

Inoltre, se sei un purista OO, gli oggetti collaborano/comunicano inviando messaggi, non leggendo/impostando lo stato.

In cambio offrono pochissimi vantaggi.Non li rimuoverei necessariamente dal codice di qualcun altro, ma non li uso personalmente.

Il problema chiave per me è che una volta protetta una variabile, non puoi consentire a nessun metodo nella tua classe di farlo fare affidamento sul fatto che il suo valore sia all'interno di un intervallo, perché una sottoclasse può sempre posizionarlo fuori intervallo.

Ad esempio, se ho una classe che definisce la larghezza e l'altezza di un oggetto renderizzabile e proteggo tali variabili, non posso fare alcuna ipotesi sulle proporzioni (ad esempio).

Criticamente, posso Mai fare queste ipotesi in qualsiasi momento dal momento in cui il codice viene rilasciato come libreria, poiché anche se aggiorno i miei setter per mantenere le proporzioni, non ho alcuna garanzia che le variabili vengano impostate tramite i setter o accessibili tramite i getter nel codice esistente.

Né alcuna sottoclasse della mia classe può scegliere di fornire tale garanzia, poiché non può nemmeno imporre i valori delle variabili, anche se questo è il punto centrale della loro sottoclasse.

Come esempio:

  • Ho una classe rettangolare con larghezza e altezza memorizzate come variabili protette.
  • Una sottoclasse ovvia (nel mio contesto) è una classe "DisplayedRectangle", dove l'unica differenza è che limito le larghezze e le altezze a valori validi per una visualizzazione grafica.
  • Ma adesso è impossibile, dal momento che la mia classe DisplayedRectangle non può vincolare veramente quei valori, poiché qualsiasi sua sottoclasse potrebbe sovrascrivere direttamente i valori, pur essendo trattata come DisplayedRectangle.

Vincolando le variabili a essere private, posso quindi imporre il comportamento che desidero tramite setter o getter.

Nella maggior parte dei casi, è pericoloso utilizzare protected perché si rompe in qualche modo l'incapsulamento della classe, che potrebbe essere interrotto da una classe derivata mal progettata.

Ma ho un buon esempio:Diciamo che puoi una sorta di contenitore generico.Ha un'implementazione interna e funzioni di accesso interne.Ma devi offrire almeno 3 accessi pubblici ai suoi dati:mappa, hash_map, simile a un vettore.Quindi hai qualcosa del tipo:

template <typename T, typename TContainer>
class Base
{
   // etc.
   protected
   TContainer container ;
}

template <typename Key, typename T>
class DerivedMap     : public Base<T, std::map<Key, T> >      { /* etc. */ }

template <typename Key, typename T>
class DerivedHashMap : public Base<T, std::hash_map<Key, T> > { /* etc. */ }

template <typename T>
class DerivedVector  : public Base<T, std::vector<T> >        { /* etc. */ }

Ho usato questo tipo di codice meno di un mese fa (quindi il codice proviene dalla memoria).Dopo averci pensato un po', credo che mentre il contenitore Base generico dovrebbe essere una classe astratta, anche se può vivere abbastanza bene, perché usare direttamente Base sarebbe così doloroso che dovrebbe essere proibito.

Riepilogo Pertanto, hai protetto i dati utilizzati dalla classe derivata.Tuttavia, dobbiamo tenere conto del fatto che la classe Base dovrebbe essere astratta.

In breve, sì.

Le variabili membro protette consentono l'accesso alla variabile da qualsiasi sottoclasse e da qualsiasi classe nello stesso pacchetto.Questo può essere molto utile, soprattutto per i dati di sola lettura.Non credo tuttavia che siano mai necessari, perché qualsiasi utilizzo di una variabile membro protetta può essere replicato utilizzando una variabile membro privata e un paio di getter e setter.

Solo per il record, sotto l'articolo 24 di "Eccezionale C ++", in una delle note a piè di pagina, Sutter Goes "Non scriverai mai una classe che ha una variabile pubblica o protetta.Giusto?(A prescindere dallo scarso esempio offerto da alcune biblioteche.)"

Per informazioni dettagliate sui modificatori di accesso .Net andare qui

Non ci sono vantaggi o svantaggi reali per le variabili membro protette, è una questione di ciò di cui hai bisogno nella tua situazione specifica.In generale è pratica accettata dichiarare le variabili membro come private e consentire l'accesso esterno tramite le proprietà.Inoltre, alcuni strumenti (es.alcuni mappatori O/R) si aspettano che i dati dell'oggetto siano rappresentati da proprietà e non riconoscono le variabili membro pubbliche o protette.Ma se sai che vuoi che le tue sottoclassi (e SOLO le tue sottoclassi) accedano a una determinata variabile, non c'è motivo per non dichiararla protetta.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top