Espacios de nombres
Variantes
Acciones

Especificadores de acceso

De cppreference.com
< cpp‎ | language
 
 
Lenguaje C++
Temas generales
Control de flujo
Instrucciones de ejecución condicionales
Instrucciones de iteración (bucles)
Declaraciones de salto
Funciones
Declaración de funciones
Declaración de funciones lambda
Especificador inline
Especificación de excepciones (hasta C++20)
Especificador noexcept (C++11)
Excepciones
Espacios de nombres
Tipos
Especificadores
decltype (C++11)
auto (C++11)
alignas (C++11)
Especificadores de duración de almacenamiento
Inicialización
Expresiones
Representaciones alternas
Literales
Booleanos - Enteros - De punto flotante
De carácter - De cadena - nullptr (C++11)
Definidos por el usuario (C++11)
Utilidades
Atributos (C++11)
Tipos
Declaración de typedef
Declaración de alias de tipo (C++11)
Conversiones
Conversiones implícitas - Conversiones explícitas
static_cast - dynamic_cast
const_cast - reinterpret_cast
Asignación de memoria
Clases
Especificadores de acceso
Especificador friend
Propiedades de funciones específicas de la clase
Funciones miembro especiales
Plantillas
Misceláneos
 

En una especificación-de-miembro de una clase, estructura o unión (class/struct o union), define la accesibilidad de los miembros subsecuentes.

En un especificador-de-base de una declaración de clase derivada, define la accesibilidad de los miembros heredados de la clase base subsecuente.

Contenido

[editar] Sintaxis

public : declaraciones-de-miembros (1)
protected : declaraciones-de-miembros (2)
private : declaraciones-de-miembros (3)
public clase-base (4)
protected clase-base (5)
private clase-base (6)
1) Los miembros declarados después del especificador tienen acceso a miembro público.
2) Los miembros declarados después del especificador tienen acceso a miembro protegido.
3) Los miembros declarados después del especificador tienen acceso a miembro privado.
4) Herencia pública: Los miembros públicos y protegidos de la clase base listados después del especificador de acceso mantienen su acceso a miembro en la clase derivada mientras que los miembros privados de la clase base son inaccesibles a la clase derivada.
5) Herencia protegida: Los miembros públicos y protegidos de la clase base listados después del especificador de acceso son miembros protegidos de la clase derivada mientras que los miembros privados de la clase base son inaccesibles a la clase derivada.
6) Herencia privada: Los miembros públicos y protegidos de la clase base listados después del especificador de acceso son miembros privados de la clase derivada mientras que los miembros privados de la clase base son inaccesibles a la clase derivada.

[editar] Explicación

El nombre de cada miembro de clase (estático, no-estático, función, tipo, etc.) tiene un "acceso a miembro" asociado. Cuando el nombre del miembro se usa en cualquier parte del programa, se comprueba su acceso, y si no satisface las reglas de acceso, el programa no compila:

#include <iostream>
 
class Ejemplo 
{
 public: // todas las declaraciones después de este punto son públicas
    void agregar(int x)   // miembro "agregar" tiene acceso público
    { 
        n += x; // de acuerdo: private Ejemplo::n puede ser accedido desde Ejemplo::agregar
    }
 private: // todas las declaraciones después de este punto son privadas
    int n = 0; // miembro "n" tiene acceso privado
};
 
int main()
{
    Ejemplo e;
    e.agregar(1); // de acuerdo: public Ejemplo::agregar puede ser accedido desde main
//  e.n = 7;  // ERROR: private Ejemplo::n no puede ser accedido desde main
}


Los especificadores de acceso le dan al autor de la clase la habilidad de decidir que miembros de clase son accesibles a los usuarios de la misma (es decir, la interfaz) y que miembros son para uso interno de la clase (la implementación).

[editar] En detalle

Todos los miembros de una clase (cuerpos de funciones miembro, inicializadores de objetos miembro, y toda las definiciones de clases anidadas) tienen acceso a todos los nombres que son accesibles a la clase. Una clase local dentro de una función miembro tiene acceso a todos los nombres accesibles a la función miembro.

Una clase definida con la palabra clave class tiene por defecto acceso privado para sus miembros y clases bases. Una clase definida con la palabra clave struct tiene por defecto acceso público para sus miembros y clases base. Una unión tiene por defecto acceso público para sus miembros.

Para permitir acceso a funciones o clases adicionales a miembros protegidos o privados, se puede usar una declaración de amistad.

La accesibilidad se aplica a todos los nombres sin tener en cuenta su origen, por lo que se comprueba un nombre introducido por typedef o declaraciones using (excepto los constructores heredados), no el nombre al que se refiere:

class A : X
{
    class B {};   // B es privado en A
public:
    typedef B BB; // BB es pública
};
 
void f()
{
    A::B y;  // error: A::B es privado
    A::BB x; // correcto: A::BB es pública
}

El acceso a miembro no afecta a la visibilidad: los nombre de miembros privados y heredados de forma privada son visibles y se tienen en cuenta para la resolución de sobrecarga, las conversiones implícitas a clase bases inaccesibles aún se consideran, etc. La verificación de acceso a miembro es el último paso después de interpretar cualquier construcción del lenguaje. La intención de esta regla es que reemplazar cualquier private con public nunca altere el comportamiento del programa.

La comprobación de acceso a los nombres usados en los argumentos de función por defecto, así como en los parámetros de plantilla por defecto, se realiza en el punto de declaración, no en el punto de uso.

Las reglas de acceso para los nombres de funciones virtuales se comprueban en el punto de llamada usando el tipo de expresión utilizada para indicar el objeto para el que se llama a la función miembro. Se ignora el acceso del reemplazo final:

struct B 
{ 
    virtual int f();   // f es pública en B
}; 
 
class D : public B 
{ 
    private: int f();  // f es privada en D
};
 
void f()
{
    D d;
    B& b = d;
 
    b.f(); // correcto: B::f es pública, se invoca a D::f aunque es privada
    d.f(); // error: D::f es privada
}

Un nombre que es privado de acuerdo con la búsqueda de nombres sin calificar, podría ser accesible a través de la búsqueda de nombres calificados:

class A {};
 
class B : private A {};
 
class C : public B
{
    A* p;   // error: la búsqueda de nombres sin calificar encuentra A como base 
            // privada de B
    ::A* q; // correcto: la búsqueda de nombres calificada encuentra la declaración 
            // a nivel de espacio de nombres
};

Un nombre que es accesible a través de varias rutas en el esquema de herencia tiene el acceso de la ruta con el mayor acceso:

class W { 
    public: void f(); 
};
 
class A : private virtual W {};
 
class B : public virtual W {};
 
class C : public A, public B
{
    void f() { 
        W::f();  // correcto: W es accesible a C a través de B
    }
};

Dentro de una clase puede aparecer cualquier número de especificadores de acceso, en cualquier orden. Los especificadores de acceso a miembros pueden afectar al diseño de la clase: solo se garantiza que las direcciones de los miembros de datos no estáticos aumenten en orden de declaración para los miembros no separados por un especificador de acceso (hasta C++11)con el mismo acceso (desde C++11).

Para los tipos de diseño estándar, todos los miembros de datos no estáticos deben tener el mismo acceso.

(desde C++11)

Cuando se redeclara un miembro dentro de la misma clase, debe hacerse con el mismo acceso a miembro:

struct S
{
    class A;    // S::A es público
private:
    class A {}; // error: no se puede cambiar el acceso
};

[editar] Acceso a miembro público

Los miembros públicos forman parte de la interfaz pública de una clase (otras partes de la interfaz pública son las funciones que no miembros encontradas por ADL).

Un miembro público de una clase es accesible en cualquier lugar:

class S
{
public:
    // n, E, A, B, C, U, f son miembros públicos
    int n;
    enum E {A, B, C};
    struct U {};
    static void f() {}
};
 
int main()
{
    S::f();     // S::f es accesible en main
 
    S s;
    s.n = S::B; // S::n y S::B son accesibles en main
 
    S::U x;     // S::U es accesible en main
}

[editar] Acceso a miembro protegido

Los miembros protegidos forman la interfaz de una clase con sus clases derivadas (que es distinta de la interfaz pública de la clase).

Un miembro protegido de una clase es accesible solamente

1) a los miembros y amigas de la clase;
2) a los miembros de cualquier clase derivada de esta, pero solo cuando la clase del objeto a través del cual se accede al miembro protegido es esa clase derivada o una clase derivada de esa clase derivada:
struct Base
{
protected:
    int i;
private:
    void g(Base& b, struct Derivada& d);
};
 
struct Derivada : Base
{
    void f(Base& b, Derivada& d) // función miembro de una clase derivada
    {
        ++d.i;                  // correcto: el tipo de d es Derivada
        ++i;                    // correcto: el tipo del '*this' implícito es Derivada
//      ++b.i;                  // error: no se puede acceder a in miembro protegido a
                                // través de Base (por contra, sería posible modificar  
                                // otras clases derivadas, como una hipotética  
                                // implementación de base Derivada2)
    }
};
 
void Base::g(Base& b, Derivada& d) // función miembro de Base
{
    ++i;                          // correcto
    ++b.i;                        // correcto
    ++d.i;                        // correcto
}
 
void x(Base& b, Derivada& d) // no miembro, no amiga
{
//  ++b.i;                  // error: no acceso desde no miembro
//  ++d.i;                  // error: no acceso desde no miembro
}

Cuando se forma un puntero a un miembro protegido, debe usarse una clase derivada en su declaración:

struct Base
{
protected:
    int i;
};
 
struct Derivada : Base
{
    void f()
    {
//      int Base::* ptr = &Base::i;     // error: se debe nombrar usando Derivada
        int Base::* ptr = &Derivada::i; // correcto
    }
};

[editar] Acceso a miembros privados

Los miembros privados forman la implementación de una clase, así como la interfaz privada para los otros miembros de la clase.

Un miembro privado de una clase solo es accesible a los miembros y amigas de esta clase, independientemente de si los miembros están en la misma o en diferentes instancias:

class S
{
private:
    int n; // S::n es privada
public:
    S() : n(10) {}                  // this->n es accesible en S::S
    S(const S& otra) : n(otra.n) {} // otra.n es accesible en S::S
};

La conversión explícita (estilo C y estilo función) permite convertir desde un lvalue derivado a una referencia a su base privada, o desde un puntero a la derivada a un puntero a su base privada.

[editar] Herencia

Para el significado de herencia pública, protegida y privada, véase clases derivadas.

[editar] Informe de defectos

Los siguientes informes de defectos de cambio de comportamiento se aplicaron de manera retroactiva a los estándares de C++ publicados anteriormente.

ID Aplicado a Comportamiento según lo publicado Comportamiento correcto
CWG 1873 C++98 los miembros protegidos eran accesibles para amigas de clases derivadas se hace inaccesible