Controllo di accesso dei membri [C++]
I controlli di accesso consentono di separare l'interfaccia public
di una classe dai dettagli di private
implementazione e dai protected
membri utilizzati solo dalle classi derivate. L'identificatore di accesso si applica a tutti i membri dichiarati dopo l'identificatore stesso, fino a quando non viene rilevato l'identificatore di accesso successivo.
class Point
{
public:
Point( int, int ) // Declare public constructor.;
Point();// Declare public default constructor.
int &x( int ); // Declare public accessor.
int &y( int ); // Declare public accessor.
private: // Declare private state variables.
int _x;
int _y;
protected: // Declare protected function for derived classes only.
Point ToWindowCoords();
};
L'accesso predefinito si trova private
in una classe e public
in uno struct o un'unione. Gli specificatori di accesso in una classe possono essere usati per un numero qualsiasi di volte in qualunque ordine. L'allocazione dell'archiviazione per oggetti di tipi di classe dipende dall'implementazione. Tuttavia, i compilatori devono garantire l'assegnazione dei membri a indirizzi di memoria più elevati tra gli identificatori di accesso.
Controllo dell'accesso ai membri
Tipo di accesso | Significato |
---|---|
private |
I membri della classe dichiarati come private possono essere usati solo dalle funzioni membro e dagli amici (classi o funzioni) della classe . |
protected |
I membri della classe dichiarati come protected possono essere usati da funzioni membro e amici (classi o funzioni) della classe . Inoltre, possono essere usati dalle classi derivate dalla classe. |
public |
I membri della classe dichiarati come public possono essere usati da qualsiasi funzione. |
Il controllo di accesso consente di impedire l'uso di oggetti in modi non destinati all'uso. Questa protezione viene persa quando si effettuano conversioni di tipi esplicite (cast).
Nota
Il controllo di accesso è ugualmente applicabile a tutti i nomi: funzioni membro, dati membro, classi annidate ed enumeratori.
Controllo di accesso nelle classi derivate
I due seguenti fattori controllano quali membri di una classe base sono accessibili in una classe derivata; questi stessi fattori controllano anche l'accesso ai membri ereditati presenti nella classe derivata:
Indica se la classe derivata dichiara la classe base utilizzando l'identificatore
public
di accesso.Quale è l'accesso ai membri presenti nella della classe base.
La tabella riportata di seguito mostra l'interazione tra questi fattori e come è possibile determinare l'accesso ai membri della classe base.
Accesso ai membri nella classe base
private |
protected |
public |
---|---|---|
Sempre inaccessibile con qualsiasi accesso alla derivazione | private nella classe derivata se si usa private la derivazione |
private nella classe derivata se si usa private la derivazione |
protected nella classe derivata se si usa protected la derivazione |
protected nella classe derivata se si usa protected la derivazione |
|
protected nella classe derivata se si usa public la derivazione |
public nella classe derivata se si usa public la derivazione |
L'esempio seguente illustra la derivazione dell'accesso:
// access_specifiers_for_base_classes.cpp
class BaseClass
{
public:
int PublicFunc(); // Declare a public member.
protected:
int ProtectedFunc(); // Declare a protected member.
private:
int PrivateFunc(); // Declare a private member.
};
// Declare two classes derived from BaseClass.
class DerivedClass1 : public BaseClass
{
void foo()
{
PublicFunc();
ProtectedFunc();
PrivateFunc(); // function is inaccessible
}
};
class DerivedClass2 : private BaseClass
{
void foo()
{
PublicFunc();
ProtectedFunc();
PrivateFunc(); // function is inaccessible
}
};
int main()
{
DerivedClass1 derived_class1;
DerivedClass2 derived_class2;
derived_class1.PublicFunc();
derived_class2.PublicFunc(); // function is inaccessible
}
In DerivedClass1
la funzione PublicFunc
membro è un public
membro ed ProtectedFunc
è un protected
membro perché BaseClass
è una public
classe base. PrivateFunc
è private
per BaseClass
ed è inaccessibile a qualsiasi classe derivata.
In DerivedClass2
le funzioni PublicFunc
e ProtectedFunc
sono considerate private
membri perché BaseClass
è una private
classe di base. Anche in questo caso, PrivateFunc
è private
a BaseClass
ed è inaccessibile a qualsiasi classe derivata.
È possibile dichiarare una classe derivata senza identificatore di accesso della classe base. In tal caso, la derivazione viene considerata private
se la dichiarazione di classe derivata usa la class
parola chiave . La derivazione viene considerata public
se la dichiarazione di classe derivata usa la struct
parola chiave . Ad esempio, il seguente codice:
class Derived : Base
...
Equivale a:
class Derived : private Base
...
In modo analogo, il seguente codice.
struct Derived : Base
...
Equivale a:
struct Derived : public Base
...
I membri dichiarati come con private
accesso non sono accessibili alle funzioni o alle classi derivate, a meno che tali funzioni o classi non vengano dichiarate usando la friend
dichiarazione nella classe base.
Un union
tipo non può avere una classe base.
Nota
Quando si specifica una private classe base, è consigliabile usare in modo esplicito la private
parola chiave in modo che gli utenti della classe derivata comprendano l'accesso ai membri.
Controllo di accesso e membri statici
Quando si specifica una classe base come private
, influisce solo sui membri non statiche. I membri statici pubblici sono ancora accessibili nelle classi derivate. Tuttavia, l'accesso ai membri della classe base tramite puntatori, riferimenti o oggetti può richiedere una conversione, che applica nuovamente il controllo di accesso. Si consideri l'esempio seguente:
// access_control.cpp
class Base
{
public:
int Print(); // Nonstatic member.
static int CountOf(); // Static member.
};
// Derived1 declares Base as a private base class.
class Derived1 : private Base
{
};
// Derived2 declares Derived1 as a public base class.
class Derived2 : public Derived1
{
int ShowCount(); // Nonstatic member.
};
// Define ShowCount function for Derived2.
int Derived2::ShowCount()
{
// Call static member function CountOf explicitly.
int cCount = ::Base::CountOf(); // OK.
// Call static member function CountOf using pointer.
cCount = this->CountOf(); // C2247: 'Base::CountOf'
// not accessible because
// 'Derived1' uses 'private'
// to inherit from 'Base'
return cCount;
}
Nel codice precedente, il controllo di accesso impedisce la conversione da un puntatore a Derived2
in un puntatore a Base
. Il this
puntatore è implicitamente di tipo Derived2 *
. Per selezionare la CountOf
funzione, this
deve essere convertita in tipo Base *
. Tale conversione non è consentita perché Base
è una private classe di base indiretta a Derived2
. La conversione in un private tipo di classe base è accettabile solo per i puntatori a classi derivate immediate. Ecco perché i puntatori di tipo Derived1 *
possono essere convertiti in tipo Base *
.
Una chiamata esplicita alla CountOf
funzione, senza usare un puntatore, un riferimento o un oggetto per selezionarla, non implica alcuna conversione. Ecco perché la chiamata è consentita.
I membri e gli amici di una classe derivata, T
, possono convertire un puntatore in T
un puntatore a una private classe base diretta di T
.
Accesso alle funzioni virtuali
Il controllo di accesso applicato alle virtual
funzioni è determinato dal tipo usato per effettuare la chiamata di funzione. L'override delle dichiarazioni della funzione non influisce sul controllo di accesso per un determinato tipo. Ad esempio:
// access_to_virtual_functions.cpp
class VFuncBase
{
public:
virtual int GetState() { return _state; }
protected:
int _state;
};
class VFuncDerived : public VFuncBase
{
private:
int GetState() { return _state; }
};
int main()
{
VFuncDerived vfd; // Object of derived type.
VFuncBase *pvfb = &vfd; // Pointer to base type.
VFuncDerived *pvfd = &vfd; // Pointer to derived type.
int State;
State = pvfb->GetState(); // GetState is public.
State = pvfd->GetState(); // C2248 error expected; GetState is private;
}
Nell'esempio precedente chiamare la funzione GetState
virtuale usando un puntatore al tipo VFuncBase
chiama VFuncDerived::GetState
e GetState
viene considerato come public
. Tuttavia, la chiamata GetState
a un puntatore al tipo VFuncDerived
è una violazione del controllo di accesso perché GetState
è dichiarata private
nella classe VFuncDerived
.
Attenzione
La funzione virtuale GetState
può essere chiamata usando un puntatore alla classe base VFuncBase
. Ciò non significa che la funzione chiamata è la versione della classe base di tale funzione.
Controllo di accesso con ereditarietà multipla
In reticoli con ereditarietà multipla che includono classi base virtuali un nome specificato può essere raggiunto da più di un percorso. Poiché a questi percorsi differenti è possibile applicare un controllo di accesso diverso, il compilatore sceglie il percorso con maggiori possibilità di accesso. Vedere la figura seguente:
Il diagramma mostra la gerarchia di ereditarietà seguente: la classe VBase è la classe base. La classe LeftPath eredita da VBase usando VBase virtuale private . La classe RightPath eredita anche da VBase ma usa VBase virtuale public . Infine, la classe Derivata eredita sia dalla classe LeftPath che dalla classe RightPath usando public LeftPath, public RightPath.
Rappresentazione grafica dell'accesso ai percorsi di un'ereditarietà
Nella figura un nome dichiarato nella classe VBase
viene sempre raggiunto tramite la classe RightPath
. Il percorso corretto è più accessibile perché RightPath
dichiara VBase
come public
classe di base, mentre LeftPath
dichiara VBase
come private
.
Vedi anche
Commenti e suggerimenti
https://aka.ms/ContentUserFeedback.
Presto disponibile: Nel corso del 2024 verranno gradualmente disattivati i problemi di GitHub come meccanismo di feedback per il contenuto e ciò verrà sostituito con un nuovo sistema di feedback. Per altre informazioni, vedereInvia e visualizza il feedback per