Pregunta Diferencia entre herencia privada, pública y protegida


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


813
2018-05-13 20:47


origen


Respuestas:


Para responder a esa pregunta, me gustaría describir los descriptores de acceso del miembro primero en mis propias palabras. Si ya lo sabe, salte al encabezado "siguiente:".

Hay tres accesorios 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) saben que Base contiene protectedMember.
  • Nadie sino Base es consciente de 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 hereda de Base.

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

902
2018-05-13 20:49



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

class B : public A
{
    // x is public
    // y is protected
    // z is not accessible from B
};

class C : protected A
{
    // x is protected
    // y is protected
    // z is not accessible from C
};

class D : private A    // 'private' is default for classes
{
    // x is private
    // y is private
    // z is not accessible from D
};

NOTA IMPORTANTE: las clases B, C y D contienen todas las variables x, y y z. Es solo cuestión de acceso.

Sobre el uso de herencia privada y protegida que podrías leer aquí.


1221
2017-09-03 11:27



Limitar la visibilidad de la herencia hará que el código no pueda ver que alguna clase hereda otra clase: las conversiones implícitas de derivadas a la base no funcionarán, y static_cast desde la base hasta el derivado tampoco funcionará.

Solo los miembros / amigos de una clase pueden ver la herencia privada, y solo los miembros / amigos y las clases derivadas pueden ver la herencia protegida.

público herencia

  1. IS-A herencia. Un botón es una ventana, y en cualquier lugar donde se necesite una ventana, también se puede pasar un botón.

    class button : public window { };
    

protegido herencia

  1. Protegido implementado en términos de. Raramente útil. Utilizada en boost::compressed_pair derivar de clases vacías y guardar memoria usando la optimización de la clase base vacía (el ejemplo a continuación no usa la plantilla para seguir en el punto):

    struct empty_pair_impl : protected empty_class_1 
    { non_empty_class_2 second; };
    
    struct pair : private empty_pair_impl {
      non_empty_class_2 &second() {
        return this->second;
      }
    
      empty_class_1 &first() {
        return *this; // notice we return *this!
      }
    };
    

privado herencia

  1. Implementado-en-términos-de. El uso de la clase base es solo para implementar la clase derivada. Útil con los rasgos y si el tamaño importa (los rasgos vacíos que solo contienen funciones harán uso de la optimización de la clase base vacía). A menudo contención es la mejor solución, sin embargo. El tamaño de las cuerdas es crítico, por lo que es un uso frecuente aquí

    template<typename StorageModel>
    struct string : private StorageModel {
    public:
      void realloc() {
        // uses inherited function
        StorageModel::realloc();
      }
    };
    

público miembro

  1. Agregar

    class pair {
    public:
      First first;
      Second second;
    };
    
  2. Accesorios

    class window {
    public:
        int getWidth() const;
    };
    

protegido miembro

  1. Proporcionar acceso mejorado para las clases derivadas

    class stack {
    protected:
      vector<element> c;
    };
    
    class window {
    protected:
      void registerClass(window_descriptor w);
    };
    

privado miembro

  1. Mantener los detalles de implementación

    class window {
    private:
      int width;
    };
    

Tenga en cuenta que los moldes de estilo C permiten deliberadamente lanzar una clase derivada a una clase base protegida o privada de una manera definida y segura, y lanzarla en la otra dirección también. Esto debe evitarse a toda costa, ya que puede hacer que el código dependa de los detalles de la implementación, pero si es necesario, puede utilizar esta técnica.


98
2017-09-03 16:04



Tiene que ver con la forma en que los miembros públicos de la clase base están expuestos desde la clase derivada.

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

Como lo señala Litb, la herencia pública es herencia tradicional que verá en la mayoría de los lenguajes de programación. Eso es, modela una relación "IS-A". La herencia privada, algo AFAIK peculiar de C ++, es una relación "IMPLEMENTADA EN TÉRMINOS DE". Eso es lo que quieres 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 derivado para reutilizar la funcionalidad de la clase base.


61
2018-05-13 20:49



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

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

enter image description here

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

si un componente es declarado como público y su clase es heredado como público la resultante acceso 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 ninguna.

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 es protegido y para variable x es ninguna.

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 clase llamada Super o eso Sub clase se deriva de la Super clase. los Sub la clase no introduce nuevas variables ni nuevas funciones. ¿Significa que cualquier objeto de la Sub la clase hereda todos los rasgos después del Super clase siendo, de hecho, una copia de un Super objetos de clase?

No. No es así

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

Cuando omitimos el especificador de visibilidad, el compilador supone que vamos a aplicar el denominado herencia privada. Significa que todo público componentes de la superclase se convierten en privado acceso, los componentes de la superclase privada no serán accesibles en absoluto. En consecuencia, significa que no está permitido usar 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 convertirá en públicos en un   de alguna manera mágica. Privado componentes permanecerán privado, públicopermanecerá público.

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

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

.

El tercer nivel de acceso se llama protegido. La palabra clave protegida significa que el componente marcado con ella se comporta como uno público cuando es utilizado por cualquiera de las subclases y se ve como privado para el resto del mundo. - Esto es cierto solo para las clases heredadas públicamente (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 puede ver en el código de ejemplo, tenemos una nueva funcionalidad para el Sub clase y hace una cosa importante: accede a la variable de almacenamiento de la clase Súper.

No sería posible si la variable se declaró como privada. En el alcance de la función principal, la variable permanece oculta de todos modos, por lo 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

40
2018-06-07 16:56



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

34
2017-09-09 05:25



1) Herencia pública:

a. Los miembros privados de la clase Base no son accesibles en la clase Derivada.

segundo. Los miembros protegidos de la clase Base permanecen protegidos en la clase Derivada.

do. Los miembros públicos de la clase Base siguen siendo públicos en la clase derivada.

Entonces, otras clases pueden usar miembros públicos de la clase Base a través del objeto de clase Derivado.

2) Herencia Protegida:

a. Los miembros privados de la clase Base no son accesibles en la clase Derivada.

segundo. Los miembros protegidos de la clase Base permanecen protegidos en la clase Derivada.

do. Los miembros públicos de la clase Base también se convierten en miembros protegidos de la clase derivada.

Por lo tanto, otras clases no pueden usar miembros públicos de la clase Base a través del objeto de clase Derivado; pero están disponibles para la subclase Derivado.

3) Herencia Privada:

a. Los miembros privados de la clase Base no son accesibles en la clase Derivada.

segundo. Los miembros protegidos y públicos de la clase Base se convierten en miembros privados de la clase derivada.

Por lo tanto, no se puede acceder a miembros de la clase Base por otras clases a través del objeto de clase Derivado ya que son privados en la clase Derivada. Entonces, incluso la subclase de Derivados la clase no puede acceder a ellos


22
2018-05-26 04:42



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

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

cada D  es un  B.

La herencia privada modela una relación IS-IMPLEMENTED-USING (o lo que se llame). Con

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

un D es no un B, pero cada D usa su B en su implementación. La herencia privada siempre se puede eliminar mediante el uso de la contención en su lugar:

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

Esta D, también, se puede implementar usando B, en este caso usando su b_. La contención es un acoplamiento menos ajustado 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 esa es una excusa poco convincente para ser flojo.

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


19
2017-09-03 12:34