c++ - Diferencia entre herencia privada, pública y protegida.




inheritance encapsulation (10)

Privado:

Solo los miembros de esa clase base pueden acceder a los miembros privados de una clase base.

Público:

Se puede acceder a los miembros públicos de una clase base por los miembros de esa clase base, los miembros de su clase derivada y los miembros que están fuera de la clase base y la clase derivada.

Protegido:

Los miembros de una clase base pueden acceder a los miembros protegidos de la clase base, así como a los miembros de su clase derivada.

En breve:

privado : base

protegido : base + derivado

público : base + derivado + cualquier otro miembro

¿Cuál es la diferencia entre public herencia public , private y protected en C ++? Todas las preguntas que he encontrado en SO tratan casos específicos.


Encontré una respuesta fácil y también pensé en publicarla para mi futura referencia.

Es de los enlaces http://www.learncpp.com/cpp-tutorial/115-inheritance-and-access-specifiers/

class Base
{
public:
    int m_nPublic; // can be accessed by anybody
private:
    int m_nPrivate; // can only be accessed by Base member functions (but not derived classes)
protected:
    int m_nProtected; // can be accessed by Base member functions, or derived classes.
};

class Derived: public Base
{
public:
    Derived()
    {
        // Derived's access to Base members is not influenced by the type of inheritance used,
        // so the following is always true:

        m_nPublic = 1; // allowed: can access public base members from derived class
        m_nPrivate = 2; // not allowed: can not access private base members from derived class
        m_nProtected = 3; // allowed: can access protected base members from derived class
    }
};

int main()
{
    Base cBase;
    cBase.m_nPublic = 1; // allowed: can access public members from outside class
    cBase.m_nPrivate = 2; // not allowed: can not access private members from outside class
    cBase.m_nProtected = 3; // not allowed: can not access protected members from outside class
}

Estas tres palabras clave también se utilizan en un contexto completamente diferente para especificar el modelo de herencia de visibilidad .

Esta tabla recopila todas las combinaciones posibles de la declaración de componentes y el modelo de herencia que presenta el acceso resultante a los componentes cuando la subclase está completamente definida.

La tabla anterior se interpreta de la siguiente manera (eche un vistazo a la primera fila):

Si un componente se declara público y su clase se hereda como pública, el acceso resultante es público .

Un ejemplo:

 class Super {
    public:      int p;
    private:     int q;
    protected:   int r;
 };

 class Sub : private Super {};

 class Subsub : public Sub {};

El acceso resultante para las variables p , q , r en la clase Subsub es ninguno .

Otro ejemplo:

class Super {
    private:     int x;
    protected:   int y;
    public:      int z;
 };
class Sub : protected Super {};

El acceso resultante para las variables y , z en la clase Sub está protegido y para la variable x es ninguno .

Un ejemplo más detallado:

class Super {
private:
    int storage;
public:
    void put(int val) { storage = val;  }
    int  get(void)    { return storage; }
};
int main(void) {
    Super object;

    object.put(100);
    object.put(object.get());
    cout << object.get() << endl;
    return 0;
}

Ahora vamos a definir una subclase:

class Sub : Super { };

int main(void) {
    Sub object;

    object.put(100);
    object.put(object.get());
    cout << object.get() << endl;
    return 0;
}

La clase definida llamada Sub, que es una subclase de la clase llamada Super o esa clase Sub , se deriva de la clase Super . La Sub no introduce nuevas variables ni nuevas funciones. ¿Significa que cualquier objeto de la clase Sub hereda todos los rasgos después de que la clase Super sea ​​de hecho una copia de los objetos de una clase Super ?

No No lo hace

Si compilamos el siguiente código, no obtendremos más que errores de compilación que put get métodos de put y get son inaccesibles. ¿Por qué?

Cuando omitimos el especificador de visibilidad, el compilador asume que vamos a aplicar la llamada herencia privada . Esto significa que todos los componentes de superclase públicos se convierten en acceso privado, los componentes de superclase privados no serán accesibles en absoluto. En consecuencia, significa que no se le permite utilizar este último dentro de la subclase.

Tenemos que informar al compilador que queremos preservar la política de acceso utilizada anteriormente.

class Sub : public Super { };

No se deje engañar : no significa que los componentes privados de la Super clase (como la variable de almacenamiento) se conviertan en públicos de una manera un tanto mágica. Los componentes privados seguirán siendo privados , los públicos seguirán siendo públicos .

Los objetos de la clase Sub pueden hacer "casi" las mismas cosas que sus hermanos mayores creados a partir de la clase Super . "Casi" porque el hecho de ser una subclase también significa que la clase perdió el acceso a los componentes privados de la superclase . No podemos escribir una función miembro de la clase Sub que podría manipular directamente la variable de almacenamiento.

Esta es una restricción muy seria. ¿Hay algún trabajo alrededor?

Si

El tercer nivel de acceso se llama protegido . La palabra clave protegida significa que el componente marcado con él se comporta como uno público cuando es usado por cualquiera de las subclases y se parece privado al resto del mundo . - Esto es cierto solo para las clases de herencia pública (como la clase Super en nuestro ejemplo) -

class Super {
protected:
    int storage;
public:
    void put(int val) { storage = val;  }
    int  get(void)    { return storage; }
};

class Sub : public Super {
public:
    void print(void) {cout << "storage = " << storage;}
};

int main(void) {
    Sub object;

    object.put(100);
    object.put(object.get() + 1);
    object.print();
    return 0;
}

Como se ve en el código de ejemplo, tenemos una nueva funcionalidad para la clase Sub y hace una cosa importante: accede a la variable de almacenamiento desde la clase Super .

No sería posible si la variable fuera declarada como privada. En el ámbito de la función principal, la variable permanece oculta de todos modos, así que si escribe algo como:

object.storage = 0;

El compilador le informará que es un error: 'int Super::storage' is protected .

Finalmente, el último programa producirá el siguiente resultado:

storage = 101

La herencia pública modela una relación IS-A. Con

class B {};
class D : public B {};

cada D es una B

La herencia privada modela una relación de USO IMPLEMENTADO-IS (o como se llame). Con

class B {};
class D : private B {};

una D no es una B , pero cada D usa su B en su implementación. La herencia privada siempre se puede eliminar utilizando la contención en su lugar:

class B {};
class D {
  private: 
    B b_;
};

Esta D , también, puede implementarse usando B , en este caso usando su b_ . La contención es un acoplamiento menos apretado entre los tipos que la herencia, por lo que en general debería preferirse. A veces, usar la contención en lugar de la herencia privada no es tan conveniente como la herencia privada. A menudo eso es una excusa poco convincente para ser perezoso.

No creo que nadie sepa qué modelos de herencia protected . Al menos no he visto ninguna explicación convincente todavía.


Para responder a esa pregunta, me gustaría describir los accesores de los miembros primero con mis propias palabras. Si ya lo sabe, pase al encabezado "siguiente:".

Hay tres accesores que conozco: public , protected y private .

Dejar:

class Base {
    public:
        int publicMember;
    protected:
        int protectedMember;
    private:
        int privateMember;
};
  • Todo lo que es consciente de Base también es consciente de que Base contiene publicMember .
  • Solo los niños (y sus hijos) son conscientes de que la Base contiene un Base protectedMember .
  • Nadie más que Base conoce a privateMember .

Por "es consciente de", me refiero a "reconocer la existencia de, y así poder acceder".

siguiente:

Lo mismo ocurre con la herencia pública, privada y protegida. Consideremos una clase Base y una clase Child que se hereda de la Base .

  • Si la herencia es public , todo lo que tiene conocimiento de Base y Child también es consciente de que Child hereda de Base .
  • Si la herencia está protected , solo el Child y sus hijos son conscientes de que heredan de la Base .
  • Si la herencia es private , nadie más que Child es consciente de la herencia.

Resumen:

  • Privado: nadie puede verlo excepto dentro de la clase.
  • Protegido: Privado + clases derivadas pueden verlo
  • Público: el mundo puede verlo.

Al heredar, puede (en algunos idiomas) cambiar el tipo de protección de un miembro de datos en cierta dirección, por ejemplo, de protegido a público.


Si hereda públicamente de otra clase, todo el mundo sabe que está heredando y cualquiera puede usarlo de forma polimórfica a través de un indicador de clase base.

Si heredas de forma protegida, solo tus clases de niños podrán usarte polimorfamente.

Si hereda de forma privada, solo usted podrá ejecutar métodos de clase padre.

Que básicamente simboliza el conocimiento que el resto de las clases tienen sobre su relación con la clase de sus padres


Tiene que ver con cómo se exponen los miembros públicos de la clase base de la clase derivada.

  • público -> los miembros públicos de la clase base serán públicos (generalmente el valor predeterminado)
  • protegido -> los miembros públicos de la clase base serán protegidos
  • privado -> los miembros públicos de la clase base serán privados

Como señala litb, la herencia pública es una herencia tradicional que se verá en la mayoría de los lenguajes de programación. Es decir, modela una relación "IS-A". La herencia privada, algo que AFAIK es peculiar de C ++, es una relación "IMPLEMENTADA EN TÉRMINOS DE". Es decir, desea utilizar la interfaz pública en la clase derivada, pero no desea que el usuario de la clase derivada tenga acceso a esa interfaz. Muchos argumentan que, en este caso, debe agregar la clase base, es decir, en lugar de tener la clase base como una base privada, hacer un miembro de derivado para reutilizar la funcionalidad de la clase base.


Accessors    | Base Class | Derived Class | World
—————————————+————————————+———————————————+———————
public       |      y     |       y       |   y
—————————————+————————————+———————————————+———————
protected    |      y     |       y       |   n
—————————————+————————————+———————————————+———————
private      |            |               |    
  or         |      y     |       n       |   n
no accessor  |            |               |

y: accessible
n: not accessible

Basado en this ejemplo para java ... Creo que una mesita vale más que mil palabras :)


Member in base class : Private   Protected   Public   

Tipo de herencia : Objeto heredado como :

Private            :   Inaccessible   Private     Private   
Protected          :   Inaccessible   Protected   Protected  
Public             :   Inaccessible   Protected   Public




c++-faq