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.
|