|
Ereditarieta` pubblica, privata e protetta
Per default l'ereditarieta` e` privata, tutti i membri ereditati diventano
cioe` membri privati della classe derivata e non sono quindi parte della sua
interfaccia. E` possibile alterare questo comportamento richiedendo un'ereditarieta`
protetta o pubblica (e` anche possibile richiedere esplicitamente l'ereditarieta`
privata), ma quello che bisogna sempre ricordare e` che non si puo` comunque
allentare il grado di protezione di un membro ereditato (i membri privati rimangono
dunque privati e comunque non accessibili alla classe derivata):
- Con l'ereditarieta` pubblica i membri ereditati mantengono lo stesso grado
di protezione che avevano nella classe da cui si eredita (classe base immediata):
i membri
public rimangono public e quelli protected continuano
ad essere protected;
- Con l'ereditarieta` protetta i membri
public della classe base divengono
membri protected della classe derivata; quelli protected rimangono
tali.
La sintassi completa per l'ereditarieta` diviene dunque:
class < DerivedClassName > : [< Qualifier >] < BaseClassName > {
/* ... */
};
dove Qualifier e` opzionale e puo` essere uno tra public,
protected e private; se omesso si assume private.
Lo standard ANSI consente anche la possibilita` di esportare singolarmente un
membro in presenza di ereditarieta` privata o protetta, con l'ovvio limite di
non rilasciare il grado di protezione che esso possedeva nella classe base:
class MyClass {
public:
void PublicMember(int, char);
void Member2();
/* ... */
protected:
int ProtectedMember;
/* ... */
private:
/* ... */
};
class Derived1 : private MyClass {
public:
MyClass::PublicMember; // esporta una specifica
// funzione membro
using MyClass::Member2; // si puo ricorrere
// anche alla using
MyClass::ProtectedMember; // Errore!
/* ... */
};
class Derived2 : private MyClass {
public:
MyClass::PublicMember; // Ok!
protected:
MyClass::ProtectedMember; // Ok!
/* ... */
};
class Derived3 : private MyClass {
public:
/* ... */
protected:
MyClass::PublicMember; // Ok era public!
MyClass::ProtectedMember; // Ok!
/* ... */
};
L'esempio mostra sostanzialmente tutte le possibili situazioni, compresa il
caso di un errore dovuto al tentativo di far diventare public un membro
che era protected.
Si noti la notazione utilizzata, non e` necessario specificare niente piu` del
semplice nome del membro preceduto dal nome della classe base e dal risolutore
di scope. Un metodo alternativo e` dato dall'uso della direttiva using
per importare nel namespace della classe derivata, un nome appartenente al namespace
della classe base.
La possibilita` di esportare singolarmente un membro e` stata introdotta per
fornire un modo semplice per nascondere all'utente della classe derivata l'interfaccia
della classe base, salvo alcune cose; si sarebbe potuto procedere utilizzando
l'ereditarieta` pubblica e ridefinendo le funzioni che non si desiderava esportare
in modo che non compiano azioni dannose, il metodo pero` presenta alcuni inconvenienti:
- Il tentativo di utilizzare una funzione non esportata viene segnalato solo
a run-time;
- E` una operazione che costringe il programmatore a lavorare di piu` aumentando
la possibilita` di errore e diminuendone la produttivita`.
D'altronde l'uso di funzioni di forward (cioe` funzioni "guscio" che servono
a richiamarne altre), risolverebbe il primo punto, ma non il secondo.
I vari "tipi" di derivazione (ereditarieta`) hanno conseguenze che vanno al
di la` della semplice variazione del livello di protezione di un membro.
Con l'ereditarieta` pubblica si modella effettivamente una relazione di tipo
Is-a poiche` la classe derivata continua ad esportare l'interfaccia
della classe base (e` cioe` possibile utilizzare un oggetto derived
come un oggetto base); con l'ereditarieta` privata questa relazione
cessa, in un certo senso possiamo vedere l'ereditarieta` privata come una sorta
di contenimento. L'ereditarieta` protetta e` invece una sorta di ibrido ed e`
scarsamente utilizzata.
|