View Full Version : [C#] metodi e campi protected
Credo che qualcosa non mi torni sulla teoria OOP in merito all'utilizzo della keyword protected...
Test banalissimo:
public class Edificio
{
public Edificio() { }
protected void entra() { ... }
}
public class Villetta : Edificio
{
public Villetta()
{
this.entra(); <---- OK. VEDO IL METODO entra()
}
}
public static void main()
{
Edificio e = new Edificio();
Villetta v = new Villetta();
e.entra() <---- NON VEDO IL METODO entra()
v.entra() <---- NON VEDO IL METODO entra()
}
Domanda.
Perche' nella sotto-classe Villetta posso vedere e chiamare il metodo entra() che ha ereditato da Edificio, mentre dal main non posso accedere al metodo entra() attraverso le istanze sia di Villetta che di Edificio?
Ikon O'Cluster
28-05-2009, 17:14
Semplicemente perchè sbagli! Guarda ora ti dico come funziona in C++ perchè in Java ho poca pratica, ma dovrebbe essere lo stesso. Hai tre possibili parole chiave:
1) private: quello che dichiari privato è visibile solo all'interno della classe e non viene ereditato dalle sottoclassi;
2) protected: quello che dichiari protetto è visibile solo all'interno della classe e viene ereditato dalle sottoclassi, quindi è visibile anche all'interno di esse;
3) public: quello che dichiari pubblico è visibile all'interno della classe, ma anche all'esterno, inoltre viene ereditato dalle sottoclassi ed è visibile in esse ed all'esterno di esse.
In particolare in C++:
nel caso in cui una sottoclasse ridefinisce un membro o una funzione protetta o pubblica, è possibile continuare a riferire la versione della superclasse attraverso l'operatore risolutore di visibilità "::".
Ikon O'Cluster
28-05-2009, 17:16
Per fare quello che vuoi fare tu, devi scrivere public e non protected, come hai fatto per il costruttore!
Semplicemente perchè sbagli! Guarda ora ti dico come funziona in C++ perchè in Java ho poca pratica, ma dovrebbe essere lo stesso. Hai tre possibili parole chiave:
1) private: quello che dichiari privato è visibile solo all'interno della classe e non viene ereditato dalle sottoclassi;
Come spiegazione per il forum va bene.
Ma se te lo dovessero chiedere ad un colloquio, la risposta giusta e':
Seppur viene ereditato nelle sottoclassi, esso non e' da esse visibile.
Un oggetto di un tipo derivato ha tutte le proprieta', campi e i metodi dei tipi padre, anche quelli privati. Solo che i privati non li potra' vedere direttamente.
Ma indirettamente si' pero'.
Pensa a quando si richiama un metodo protected o public derivato dalla classe padre, il quale a sua volta fa uso di un metodo o un campo privato della stessa classe padre.
Se il metodo o campo privato in questione non esistesse, ovvero se non fosse ereditato seppur invisibile alla classe figlia, si avrebbe un'anomalia.
Allora... devo ragionarci un po' su per capire bene perche' mi e' sempre sembrato banale e invece...
Quello che sicuramente mi sembra piu' strano e' che la stessa classe Edificio non puo' chiamare il metodo protected entra() attraverso un'istanza di se stesso... eppure il metodo e' praticamente il suo... non e' stato ereditato da nessuna classe ancora superiore gerarchicamente!
Allora... devo ragionarci un po' su per capire bene perche' mi e' sempre sembrato banale e invece...
Quello che sicuramente mi sembra piu' strano e' che la stessa classe Edificio non puo' chiamare il metodo protected entra() attraverso un'istanza di se stesso... eppure il metodo e' praticamente il suo... non e' stato ereditato da nessuna classe ancora superiore gerarchicamente!
Il fatto e' che si puo' richiamare solo DA DENTRO la classe stessa.
Quel pezzo di main non e' dentro la classe stessa, quindi ne le protected ne tantomento le private possono essere richiamate.
E' il concetto dell'incapsulamento dell OO.
http://it.wikipedia.org/wiki/Incapsulamento_(informatica)
Mmm. Beh io fino ad ora il concetto di incapsulamento l'avevo sempre pensato cosi:
"un oggetto istanza di una classe A, puo' accedere ai metodi e ai campi di un oggetto di una classe B solo se questi sono dichiarati public, o nel caso in cui questi siano dichiarati protected e la classe A sia derivata dalla classe B"
Invece a questo punto il concetto come lo pensavo io e' valido solo per campi e metodi public. Mentre con protected o private le regole rispettive si applicano ma all'interno della classe, e non centrano piu' nulla le istanze.
:confused:
Ikon O'Cluster
28-05-2009, 19:35
X gugoXX: lo so era una spiegazione approssimativa. L'utente che ha posto la domanda è all'inizio quindi volevo risparmiargli le complicazioni del caso. Certamente al professore di Fondamenti di Informatica II non ho risposto così :D :D :D Se però mcaisco chiede di più si può pure approfondire, ma preferisco sempre una programmazione del cervello umano strutturata a livelli :) modularità applicata alla vita umana :p
X mcaisco: Ti sfugge il concetto di classe! Tutto qua. Se conosci quello capisci anche cosa è l'incapsulamento anche detto "information hiding". Adesso ti spiego meglio, perchè potrebbe essere utile a molti altri alle prime armi con questi concetti (come diceva il mio Prof. se uno di voi fa una domanda, ce ne sono almeno altri 10 che hanno lo stesso dubbio). Partiamo dalla base: considera una variabile di tipo "int", questa è un "tipo di dato". Una variabile "double" è un "tipo di dato". Anche la classe è un tipo di dato. In quanto tale è caratterizzata da 2 elementi:
1) Una rappresentazione interna del tipo di dato, ovvero il modo in cui il tipo viene rappresentato nella memoria. A livello astratto ciò si traduce in una cosa che chiamiamo "valore" che possiamo assegnare al tipo. In un certo momento dell'esecuzione i valori assegnati ad una istanza del tipo di dato ne costituiscono lo "stato".
2) Operazioni concrete intese come istruzioni macchina che possono lavorare sulle rappresentazioni dei dati. A livello astratto parliamo di "operazioni di alto livello". Queste permettono di far variare i "valori" dell'istanza del tipo di dato e quindi di farne evolvere lo "stato". Queste operazioni costituiscono l'unico punto di accesso alla rappresentazione interna del tipo, il quale quindi non può essere modificato altrimenti.
L'information hiding, significa proprio nascondere i valori all'interno di una membrana protettiva che può essere oltrepassata solo dalle operazioni che il tipo di dato definisce. Perciò se vuoi modificare il tipo int puoi usare =, +, -, *, ecc... ma oltre a questi operatori non hai altro modo per metterci su le mani.
Una classe realizza il medesimo comportamento attraverso:
1) Campi membro
2) Funzioni membro
In una prima analisi possiamo pensare quindi ai campi membro come un insieme di tipi primitivi e non che possono essere acceduti solo dalle funzioni membro della classe. Quindi all'esterno della classe tu vedi solo le funzioni membro, non gli int, i double, ecc... (campi membro) che costituiscono i membri interni alla classe.
Il discorso si complica quando generalizzi i concetti. In realtà la distinzione non è tra campi membro e funzioni membro, ma tra membri privati e membri pubblici.
Un membro privato è quello che sta all'interno della membrana.
Un membro pubblico è al confine della membrana e può essere visto all'esterno di essa, ma è l'unico punto di accesso per operare sulla parte privata che sta all'interno.
Per membro quindi ci può essere tanto un campo (caratterizzato a sua volta in un tipo di dato che può non essere primitivo) tanto una funzione.
Pertanto abbiamo già una certa tassonomia:
1) Campi privati
2) Campi pubblici
3) Funzioni private
4) Funzioni pubbliche
Chi usa la classe può riferire i campi e le funzioni pubbliche e basta. Mentre le funzioni private possono essere chiamate solo dalle funzioni pubbliche.
Se non consideri la derivazione, definire una funzione protected o private è la stessa cosa! Di fatto si può dire che è indifferente l'uso di un classificatore o dell'altro. Per chiarirti le idee pensa di usare sempre "private" e non "protected" (e non preoccuparti del meccanismo della derivazione). In questo caso la funzione membro entra() non potrebbe essere invocata dall'esterno della classe perchè è una funzione privata!!!
Allora xkè discriminare tra protected e private???
Qui entra in gioco la derivazione... La derivazione è il gioco delle scatole cinesi: se tu derivi una classe non hai fatto altro che prendere una scatola più grande e metterci dentro la superclasse cioè la scatola più piccola! A questo punto mi devo chiedere la seguente domanda:
Chi sta all'interno della scatola grande (la sottoclasse) cosa vede della scatola piccola (della superclasse)???
Vede sicuramente gli unici punti di accesso pubblici e quindi i membri pubblici. Pertanto ciò che è pubblico nella superclasse è pubblico nella sottoclasse
Ma i membri privati? No quelli non sono visibili all'esterno della superclasse e quindi non saranno visibili nemmeno all'esterno della sottoclasse!
E la via di mezzo qual è??? Il membro protetto. Il membro protetto non è visibile all'esterno della superclasse (perchè è come se fosse privato), non è visibile all'esterno della sottoclasse (perchè continua a comportarsi come se fosse privato). Differisce però dai membri privati, per il fatto che una qualsiasi funzione membro della sottoclasse (qualunque sia il suo genere) riesce a vederlo! Cosa che non succedeva con il membro privato!
Ora preparo alcuni esempi chiarificatori!
Ikon O'Cluster
28-05-2009, 19:36
Non guardate la sintassi, ma solo la semantica del seguente codice:
class Superclasse {
private campi_membro_privati_superclasse;
protected campi_membro_protetti_superclasse;
public campi_membro_pubblici_superclasse;
private void funzioni_membro_private_superclasse();
protected void funzioni_membro_protette_superclasse();
public void funzioni_membro_pubbliche_superclasse();
}
class Sottoclasse : Superclasse {
private campi_membro_privati_sottoclasse;
protected campi_membro_protetti_sottoclasse;
public campi_membro_pubblici_sottoclasse;
private void funzioni_membro_private_sottoclasse();
protected void funzioni_membro_protette_sottoclasse();
public void funzioni_membro_pubbliche_sottoclasse();
}
Vediamo cosa vedo dal main:
Superclasse super;
Sottoclasse sotto;
super.campi_membro_privati_superclasse; //errore
super.campi_membro_protetti_superclasse; //errore
super.campi_membro_pubblici_superclasse; // visibile
super.funzioni_membro_private_superclasse(); //errore
super.funzioni_membro_protette_superclasse(); //errore
super.funzioni_membro_pubbliche_superclasse(); //visibile
sotto.campi_membro_privati_superclasse; //errore
sotto.campi_membro_protetti_superclasse; //errore
sotto.campi_membro_pubblici_superclasse; // visibile
sotto.campi_membro_privati_sottoclasse; //errore
sotto.campi_membro_protetti_sottoclasse; //errore
sotto.campi_membro_pubblici_sottoclasse; // visibile
sotto.funzioni_membro_private_superclasse(); //errore
sotto.funzioni_membro_protette_superclasse(); //errore
sotto.funzioni_membro_pubbliche_superclasse(); //visibile
sotto.funzioni_membro_private_sottoclasse(); //errore
sotto.funzioni_membro_protette_sottoclasse(); //errore
sotto.funzioni_membro_pubbliche_sottoclasse(); //visibile
Inoltre supponiamo di essere all'interno della definizione di Sottoclasse::funzioni_membro_pubbliche_sottoclasse(), sarà visibile:
Superclasse::campi_membro_privati_superclasse; //errore
Superclasse::campi_membro_protetti_superclasse; //visibile
Superclasse::campi_membro_pubblici_superclasse; // visibile
Superclasse::funzioni_membro_private_superclasse(); //errore
Superclasse::funzioni_membro_protette_superclasse(); //visibile
Superclasse::funzioni_membro_pubbliche_superclasse(); //visibile
Sottoclasse::campi_membro_privati_sottoclasse; //visibile
Sottoclasse::campi_membro_protetti_sottoclasse; //visibile
Sottoclasse::campi_membro_pubblici_sottoclasse; // visibile
Sottoclasse::funzioni_membro_private_sottoclasse(); //visibile
Sottoclasse::funzioni_membro_protette_sottoclasse(); //visibile
Sottoclasse::funzioni_membro_pubbliche_sottoclasse(); //visibile
Spero sia chiaro anche se non formale...
^TiGeRShArK^
28-05-2009, 20:23
ma non è che semplicemente volevi definirlo come internal o internal protected? :mbe:
quando è definito come internal allora tutte le classi dello stesso progetto possono accedervi, con internal protected, vi possono accedere tutte le sottoclassi e tutte le classi dello stesso progetto se non erro....
Ikon O'Cluster
28-05-2009, 20:38
internal???
^TiGeRShArK^
28-05-2009, 21:01
internal???
:mbe:
si...
non stavamo parlando di C#? :fagiano:
mi pare che internal è nel C# e nel java c'è package come visibilità, sempre se non ricordo male....
Ikon O'Cluster
28-05-2009, 21:37
No chiedevo per sapere che roba era :)
^TiGeRShArK^
28-05-2009, 21:40
No chiedevo per sapere che roba era :)
è una parola chiave per definire la visibilità nel c# che dovrebbe essere equivalente alla visibilità di tipo package in java (che è quella di default) se non mi sto dimenticando niente. :p
Grazie a tutti per le correzioni.
In realta' non sono alle prime armi ma evidentemente avevo sempre applicato l'incapsulamento/ereditarieta' in maniera corretta senza aver compreso che la visibilita' e' a livello di classe e non anche di istanza... io pensavo che valesse per entrambi. Evidentemente fino ad ora l'avevo applicata bene senza incappare mai in errori... fino a ieri!
Beh meglio cosi'. Ora non ci casco piu'.
Comunque la domanda era inizialmente inerente a C# perche' pensavo che quel comportamento fosse di C#. Invece a questo punto e' proprio il comportamento standard del modificatore protected in OOP.
Credo che il modificatore "protected internal" di C# imponga la visibilita' a livello di assembly .net, cioe' tutte le classi appartenenti ad uno stesso assembly .net vedono quei campi o quei metodi internal protected. Diciamo che e' un livello di visibilita' superiore al package di java, il quale invece in C# e' tradotto con il concetto di namespace. Infatti in uno stesso assembly .net ci possono essere piu' namespace (package).
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.