Membri privati ​​e protetti: C ++


276

Qualcuno può illuminarmi sulla differenza tra privatee protectedmembri nelle classi?

Ho capito da migliori convenzioni practice che le variabili e le funzioni che non sono chiamati fuori della classe dovrebbero essere private- ma guardando il mio MFC progetto, MFC sembra favorire protected.

Qual è la differenza e quale dovrei usare?

Risposte:


374

I membri privati ​​sono accessibili solo all'interno della classe che li definisce.

I membri protetti sono accessibili nella classe che li definisce e nelle classi che ereditano da quella classe.

Modifica: entrambi sono accessibili anche dagli amici della loro classe e, nel caso dei membri protetti, dagli amici delle loro classi derivate.

Modifica 2: usa tutto ciò che ha senso nel contesto del tuo problema. Dovresti provare a rendere i membri privati ​​ogni volta che puoi per ridurre l'accoppiamento e proteggere l'implementazione della classe base, ma se ciò non è possibile usa i membri protetti. Consulta le domande frequenti su C ++ per una migliore comprensione del problema. Questa domanda sulle variabili protette potrebbe anche aiutare.


12
Il link alle domande frequenti su C ++ Lite è stato spostato su isocpp.org/wiki/faq/basics-of-inheritance
avner

134

I membri pubblici di una classe A sono accessibili a tutti e tutti.

I membri protetti di una classe A non sono accessibili al di fuori del codice A, ma sono accessibili dal codice di qualsiasi classe derivata da A.

I membri privati di una classe A non sono accessibili al di fuori del codice A o dal codice di qualsiasi classe derivata da A.

Quindi, alla fine, scegliere tra protetto o privato sta rispondendo alle seguenti domande: Quanta fiducia sei disposto a riporre nel programmatore della classe derivata?

Per impostazione predefinita , supponiamo che la classe derivata non sia attendibile e rendi i tuoi membri privati . Se hai un'ottima ragione per dare libero accesso agli interni della classe madre alle sue classi derivate, allora puoi renderli protetti.


La classe derivata dovrebbe essere un tipo di classe e i dati protetti della classe base fanno parte dei dati della classe derivata. Il writer della classe derivata deve gestire correttamente questi dati o è un bug. I dati privati ​​in una classe base sono, tuttavia, qualcosa che il writer della classe derivata non controlla.
CashCow,

@CashCow the protected data of the base class is part of the data of the derived class.In effetti. Non è meglio, quindi, che lo scrittore della classe derivata dichiari che i dati nella loro classe, anziché i miei? ... :-) ... The writer of the derived class is expected to handle this data properly or it is a bug.Nel modello NVI, l'obiettivo è quello di rendere tutto privato, incluso metodi, per limitare il danno che il writer di classe derivato potrebbe causare alla gerarchia. I metodi protetti sono già un potenziale problema. Non sono convinto che aggravare ciò usando lo stato protetto sia l'approccio giusto.
paercebal,

Potrebbe essere, il che richiederebbe di avere "getter" virtuali nella classe base per accedervi. E mentre puoi avere classi intermedie per fare i diversi modi in cui il modello di dati può essere implementato, non è sempre pratico farlo. Ad esempio, uno "schema", comune nei linguaggi che non hanno un modificatore "const" sebbene non sia necessario il più delle volte in C ++ è di avere una classe di base di sola lettura e classi derivate scrivibili. In C ++ questo può anche essere utile semplicemente perché vuoi più di un modo possibile per caricare (inizializzare) i dati.
CashCow,

Ci sono vari modi per farlo. Rendi amici i tuoi corsi di serializzazione. Metti tutti i tuoi dati in una struttura con accesso pubblico ma la tua classe ha un membro privato di questa variabile .... Membri protetti e classi derivate per caricarli da qualunque fonte a volte è più facile.
CashCow,

63

È possibile accedere ai membri protetti da classi derivate. Quelli privati ​​non possono.

class Base {

private: 
  int MyPrivateInt;
protected: 
  int MyProtectedInt;
public:
  int MyPublicInt;
};

class Derived : Base
{
public:
  int foo1()  { return MyPrivateInt;} // Won't compile!
  int foo2()  { return MyProtectedInt;} // OK  
  int foo3()  { return MyPublicInt;} // OK
};‌‌

class Unrelated 
{
private:
  Base B;
public:
  int foo1()  { return B.MyPrivateInt;} // Won't compile!
  int foo2()  { return B.MyProtectedInt;} // Won't compile
  int foo3()  { return B.MyPublicInt;} // OK
};

In termini di "migliori pratiche", dipende. Se c'è anche una debole possibilità che qualcuno possa voler derivare una nuova classe da quella esistente e avere bisogno dell'accesso ai membri interni, rendili protetti, non privati. Se sono privati, la tua classe potrebbe diventare difficile da ereditare facilmente.


3
Mi permetto di dissentire: se c'è una debole possibilità che nessuna sottoclasse ne abbia bisogno, rendila privata. A meno che non si ha intenzione di avere il vostro classe sottoclasse, utilizzare il modello Template Method.
xtofl,

23

Il motivo per cui MFC preferisce la protezione è perché è un framework. Probabilmente si desidera sottoclassare le classi MFC e in tal caso è necessaria un'interfaccia protetta per accedere a metodi che non sono visibili all'uso generale della classe.


9

Tutto dipende da cosa vuoi fare e da cosa puoi vedere le classi derivate.

class A
{
private:
    int _privInt = 0;
    int privFunc(){return 0;}
    virtual int privVirtFunc(){return 0;}
protected:
    int _protInt = 0;
    int protFunc(){return 0;}
public:
    int _publInt = 0;
    int publFunc()
    {
         return privVirtFunc();
    }
};

class B : public A
{
private:
    virtual int privVirtFunc(){return 1;}
public:
    void func()
    {
        _privInt = 1; // wont work
        _protInt = 1; // will work
        _publInt = 1; // will work
        privFunc(); // wont work
        privVirtFunc(); // wont work
        protFunc(); // will work
        publFunc(); // will return 1 since it's overridden in this class
    }
}

6

Attributi e metodi contrassegnati come protectedsono - a differenza di quelli privati ​​- ancora visibili nelle sottoclassi.

A meno che tu non voglia usare o fornire la possibilità di sovrascrivere il metodo in possibili sottoclassi, li farei private.


2
Una classe derivata può sovrascrivere le funzioni virtuali private della sua base
James Hopkin,

6

Dai un'occhiata alla domanda sulle variabili dei membri protetti . Si consiglia di utilizzare private come predefinito (proprio come fanno C ++ class) per ridurre l'accoppiamento. Le variabili membro protette sono sempre una cattiva idea, le funzioni membro protette possono essere utilizzate ad es. Per il modello Metodo modello.


Divertente, l'ho modificato nel mio post prima di vedere il tuo. Eseguito l'upgrade perché gli uccelli di una piuma inciampano sullo stesso anello :)
Firas Assaad,

4

I membri protetti possono accedere solo ai discendenti della classe e al codice nello stesso modulo. Ai membri privati ​​è possibile accedere solo dalla classe in cui sono dichiarati e dal codice nello stesso modulo.

Naturalmente le funzioni degli amici lo buttano fuori dalla finestra, ma vabbè.


4

i membri privati ​​sono accessibili solo all'interno della classe, i membri protetti sono accessibili nella classe e le classi derivate. È una caratteristica dell'ereditarietà nelle lingue OO.

È possibile avere un'eredità privata, protetta e pubblica in C ++, che determinerà a quali classi derivate può accedere nella gerarchia dell'ereditarietà. C # per esempio ha solo eredità pubblica.


3

privato = accessibile solo dalla nave madre (classe base) (cioè solo il mio genitore può andare nella camera dei miei genitori)

protetto = accessibile dalla nave madre (classe base) e dalle sue figlie (cioè solo il mio genitore può andare nella camera dei miei genitori, ma ha dato a figlio / figlia il permesso di entrare nella camera dei genitori)

pubblico = accessibile dalla nave madre (classe base), dalla figlia e da tutti gli altri (cioè solo i miei genitori possono andare nella camera dei miei genitori, ma è una festa in casa - mi casa su casa)


2

Poiché non è necessaria alcuna funzione di membro pubblico per recuperare e aggiornare i membri protetti nella classe derivata, ciò aumenta l'efficienza del codice e riduce la quantità di codice che dobbiamo scrivere. Tuttavia, il programmatore della classe derivata dovrebbe essere consapevole di ciò che sta facendo.


È sempre possibile utilizzare una funzione incorporata implementata nella dichiarazione di classe. Il compilatore lo ottimizzerà via (e sarebbe un buon modo per imporre l'accesso in sola lettura a una variabile membro privata, per esempio).
Paul Sanders,

2

privateè preferito per i dati dei membri. I membri nelle classi C ++ sono privatepredefiniti.

publicè preferito per le funzioni membro, anche se è una questione di opinione. Almeno alcuni metodi devono essere accessibili. publicè accessibile a tutti. È l'opzione più flessibile e meno sicura. Chiunque può usarli e chiunque può abusarli.

privatenon è affatto accessibile. Nessuno può usarli al di fuori della classe e nessuno può abusarne. Nemmeno nelle classi derivate.

protectedè un compromesso perché può essere utilizzato nelle classi derivate. Quando provieni da una classe, hai una buona comprensione della classe di base e stai attento a non abusare di questi membri.

MFC è un wrapper C ++ per l'API di Windows, che preferisce publice protected. Classi generate da Visual Studio Wizard hanno un brutto mix di protected, publice privatemembri. Ma c'è qualche logica nelle stesse classi MFC.

I membri come lo SetWindowTextsono publicperché spesso è necessario accedere a questi membri.

Membri come OnLButtonDowngestiscono le notifiche ricevute dalla finestra. Non dovrebbero essere accessibili, quindi lo sono protected. È comunque possibile accedervi nella classe derivata per sovrascrivere queste funzioni.

Alcuni membri devono eseguire thread e loop di messaggi, non è necessario accedervi o sostituirli, quindi vengono dichiarati come private

Nelle strutture C ++, i membri sono publicper impostazione predefinita. Le strutture sono generalmente utilizzate solo per dati, non per metodi, pertanto la publicdichiarazione è considerata sicura.


1
Scrivi "I membri nelle classi C ++ sono protetti per impostazione predefinita". Secondo lo standard, sono o privati ​​o pubblici per impostazione predefinita, a seconda della parola chiave utilizzata nella definizione (14p3). Microsoft si discosta dallo standard qui?
Alexander Klauer,

@AlexanderKlauer Ho sbagliato, è di privatedefault in Visual Studio. È di privatedefault anche in gcc, non è mai publicdi default. A meno che non mi sbagli di nuovo. Non riesco a trovare lo standard a cui ti riferisci.
Barmak Shemirani,

Scusa, avrei dovuto essere più specifico. Mi riferivo allo standard C ++ 17. Lo standard C ++ 11 ha la stessa formulazione in 11p3. Potresti aggiornare la tua risposta? Grazie!
Alexander Klauer,

1

È possibile accedere a un membro privato solo nella stessa classe in cui ha dichiarato dove è possibile accedere come membro protetto nella classe in cui è dichiarato insieme alle classi che sono ereditate da esso.


1
  • Privato : è un identificatore di accesso. Per impostazione predefinita, le variabili di istanza (membro) oi metodi di una classe in c ++ / java sono privati. Durante l'ereditarietà, il codice e i dati vengono sempre ereditati ma non sono accessibili al di fuori della classe. Possiamo dichiarare i nostri membri dei dati come privati ​​in modo che nessuno possa apportare modifiche dirette alle variabili dei nostri membri e possiamo fornire getter e setter pubblici al fine di cambiare i nostri membri privati. E questo concetto viene sempre applicato nella regola aziendale.

  • Protetto : è anche un identificatore di accesso. In C ++, i membri protetti sono accessibili all'interno della classe e alla classe ereditata ma non al di fuori della classe. In Java, i membri protetti sono accessibili all'interno della classe, sia alla classe ereditata che a tutte le classi all'interno dello stesso pacchetto.


0

Un membro protetto della classe base non statica può accedere ai membri e agli amici di qualsiasi classe derivata da quella classe base utilizzando una delle seguenti opzioni:

  • Un puntatore a una classe derivata direttamente o indirettamente
  • Un riferimento a una classe derivata direttamente o indirettamente
  • Un oggetto di una classe derivata direttamente o indirettamente

0

Privato: accessibile dalle funzioni dei membri della classe e dalla funzione amico o dalla classe amico. Per la classe C ++ si tratta dell'identificatore di accesso predefinito.

Protetto: accessibile da funzioni membro della classe, funzione amico o classe amico e classi derivate.

  • Puoi mantenere la variabile o la funzione del membro della classe (anche typedef o classi interne) come privata o protetta secondo le tue esigenze.
  • Il più delle volte si mantiene un membro della classe come privato e si aggiungono funzioni get / set da incapsulare. Questo aiuta a mantenere il codice.
  • La funzione generalmente privata viene utilizzata quando si desidera mantenere modulari le funzioni pubbliche o eliminare il codice ripetuto anziché scrivere l'intero codice in un'unica funzione. Questo aiuta a mantenere il codice.

Fare riferimento a questo link per maggiori dettagli.


-2

I modificatori di accesso privato e protetto sono gli stessi a cui è possibile accedere ai membri protetti della classe base al di fuori dell'ambito della classe base nella classe figlio (derivata). Lo stesso vale anche per l'eredità. Ma con il modificatore privato è possibile accedere ai membri della classe base solo nell'ambito o nel codice della classe base e le sue funzioni amiche solo '' ''


5
Quale valore aggiunge la tua risposta rispetto alle altre risposte?
Hermann Döppes,
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.