Condividi tramite


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 DerivedClass1la funzione PublicFunc membro è un public membro ed ProtectedFunc è un protected membro perché BaseClass è una public classe base. PrivateFunc è private per BaseClassed è inaccessibile a qualsiasi classe derivata.

In DerivedClass2le funzioni PublicFunc e ProtectedFunc sono considerate private membri perché BaseClass è una private classe di base. Anche in questo caso, PrivateFunc è private a BaseClassed è 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::GetStatee 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:

Diagram showing access along the paths of an inheritance graph.

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

Riferimenti al linguaggio C++