Diferencia entre herencia privada, pública y protegida

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

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 usuarios que conozco: public , protected y private .

Dejar:

 class Base { public: int publicMember; protected: int protectedMember; private: int privateMember; }; 
  • Todo lo que conoce de Base también sabe que Base contiene publicMember .
  • Solo los niños (y sus hijos) saben que Base contiene 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 sucede 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 conoce de Base y Child también es consciente de que Child hereda de Base .
  • Si la herencia está protected , solo Child y sus hijos saben que heredan de Base .
  • Si la herencia es private , nadie más que el Child conoce la herencia.
 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.

Acerca del uso de herencia privada y protegida que puede leer aquí .

Limitar la visibilidad de la herencia hará que el código no pueda ver que una clase hereda otra clase: las conversiones implícitas desde la derivada a la base no funcionarán, y static_cast desde la base hasta la derivada 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.

herencia pública

  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 { }; 

herencia protegida

  1. Protegido implementado en términos de. Raramente útil. Usado en boost::compressed_pair para derivar de clases vacías y guardar memoria usando la optimización de 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! } }; 

herencia privada

  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). Sin embargo, a menudo la contención es la mejor solución. El tamaño de las cuerdas es crítico, por lo que es un uso frecuente aquí

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

miembro público

  1. Agregar

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

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

miembro protegido

  1. Proporcionar acceso mejorado para las clases derivadas

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

miembro privado

  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.

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 progtwigció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”. 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 derivado para reutilizar la funcionalidad de la clase base.

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 statement 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 se declara como 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 no 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 no 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 clase llamada Super o esa Sub se deriva de la Super clase. La Sub no presenta nuevas variables ni nuevas funciones. ¿Significa que cualquier objeto de la Sub hereda todos los rasgos después de que la clase Super sea ​​en realidad una copia de los objetos de una Super clase?

No No es así

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

Cuando omitimos el especificador de visibilidad, el comstackdor supone que vamos a aplicar la llamada herencia privada . Significa que todos los componentes de la superclase pública se convierten en acceso privado, 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 comstackdor 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 clase Super (como la variable de almacenamiento) se convertirán en públicos de una manera algo mágica. Los componentes privados seguirán siendo privados , el público seguirá siendo público .

Los objetos de la Sub pueden hacer "casi" lo mismo 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ó acceso a los componentes privados de la superclase . No podemos escribir una función miembro de la clase Sub que pueda 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 él se comporta como uno público cuando se utiliza en cualquiera de las subclases y se ve como privado para el rest del mundo . - Esto es cierto solo para las clases heredadas públicamente (como la clase Súper 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 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 de la clase Super .

No sería posible si la variable se declaró como privada. En el scope de la función principal, la variable permanece oculta de todos modos, por lo que si escribe algo como:

 object.storage = 0; 

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

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

 storage = 101 
 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 

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 clase derivada no puede acceder a ellos.

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 {}; 

a D no es 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 puede implementarse 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 qué modelos de herencia protected . Al menos no he visto ninguna explicación convincente todavía.

Si heredas públicamente de otra clase, todos saben que estás heredando y puedes ser usado polimórficamente por cualquiera a través de un puntero de clase base.

Si heredas de forma protegida, solo tus hijos podrán utilizarlo polimórficamente.

Si heredas privadamente, solo tú mismo podrás ejecutar los métodos de la clase para padres.

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

A las clases heredadas de su clase se puede acceder a los miembros de datos protegidos. Los miembros de datos privados, sin embargo, no pueden. Digamos que tenemos lo siguiente:

 class MyClass { private: int myPrivateMember; // lol protected: int myProtectedMember; }; 

Desde dentro de su extensión hasta esta clase, hacer referencia a this.myPrivateMember no funcionará. Sin embargo, this.myProtectedMember hará. El valor aún está encapsulado, por lo que si tenemos una instanciación de esta clase llamada myObj , entonces myObj.myProtectedMember no funcionará, por lo que es similar en función a un miembro de datos privados.

Resumen:

  • Privado: nadie puede verlo excepto dentro de la clase
  • Protegido: clases privadas + 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.

 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 este ejemplo para Java … creo que una pequeña mesa vale más que mil palabras 🙂

Privado:

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

Público:

A los miembros públicos de una clase base se puede acceder 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:

A los miembros de una clase base se puede 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

public : base + derived + cualquier otro miembro

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

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 } 

Es esencialmente la protección de acceso de los miembros públicos y protegidos de la clase base en la clase derivada. Con la herencia pública, la clase derivada puede ver miembros públicos y protegidos de la base. Con herencia privada, no puede. Con protected, la clase derivada y cualquier clase derivada de eso pueden verlas.

Intereting Posts