programacion poo orientada objetos hijo herencia ejemplos derivadas derivada clases clase c++

c++ - poo - ¿Cómo heredar públicamente de una clase base pero hacer que algunos de los métodos públicos de la clase base sean privados en la clase derivada?



herencia poo (7)

Por ejemplo, la clase Base tiene dos métodos públicos: foo() y bar() . La Clase Derived se hereda de la clase Base . En la clase Derived , quiero hacer que foo() público pero bar() privado. ¿Es el siguiente código la forma correcta y natural de hacer esto?

class Base { public: void foo(); void bar(); }; class Derived : public Base { private: void bar(); };


De acuerdo con el Principio de Sustitución de Liskov , la herencia pública debe modelar "is-a". Lo que está diciendo con Derived heredando públicamente de Base es que siempre que se requiera un objeto Base , un objeto de tipo Derived lo hará.

Si necesita Derived para ocultar algunas operaciones que están disponibles para Base , entonces lo que está modelando es algo distinto a "is-a", y la herencia pública no es la herramienta correcta.

Lo que desea es herencia privada o composición, como otras respuestas han detallado.


Digamos que tienes esto:

class Foo{ public: void method1(); void method2(); void notGonnaSeeIt(); private: //stuff };

Para envolverlo de manera efectiva, puede hacer una herencia privada y pasar los métodos que desea a una declaración pública como sugirió Brian:

class Bar : private Foo{ void methodA(){ method1(); } void methodB(){ method2(); } //more stuff };

o puedes envolverlo con un decorador

template<class T> class Bar{ public: Bar(T *_input) : m_Input(_input){} void methodA() { m_Input->method1(); } void methodB() { m_Input->method2(); } //whatever else you need/want private: T* m_Input; };

Personalmente, prefiero la forma de la plantilla, ya que te permite hacer lo mismo con cualquier clase que herede de Foo .


La sección 11.3 del estándar C ++ ''03 describe esta habilidad:

11.3 Declaraciones de acceso
El acceso de un miembro de una clase base puede modificarse en la clase derivada al mencionar su id-calificado en la declaración de clase derivada. Tal mención se llama una declaración de acceso. El efecto de una declaración de acceso con id-calificado; se define como equivalente a la declaración que utiliza id calificado

Entonces hay 2 formas en que puedes hacerlo.

Nota: A partir de ISO C ++ ''11, las declaraciones de acceso ( Base::bar; ) están prohibidas como se indica en los comentarios. En su lugar, se debe usar una declaración de using Base::bar; ( using Base::bar; ).

1) Puede usar la herencia pública y luego hacer que la barra sea privada:

class Base { public: void foo(){} void bar(){} }; class Derived : public Base { private: using Base::bar; };

2) Puedes usar herencia privada y luego hacer foo público:

class Base { public: void foo(){} void bar(){} }; class Derived : private Base { public: using Base::foo; };

Nota: Si tiene un puntero o referencia de tipo Base que contiene un objeto de tipo Derivado, el usuario podrá llamar al miembro.


Primero, debes entender lo que quieres hacer desde la perspectiva de OOP. Hay dos tipos de herencia completamente diferentes:

  1. Herencia de la interfaz. Es cuando implement en Java u otros lenguajes que tienen interfaces como entidades independientes, también ocurre cuando hereda públicamente de una clase abstracta vacía en C ++. Aquí no le importa el código, pero quiere decirle a su compilador y a todos los que utilizan clases base / derivadas que esta clase derivada es un tipo especial de su clase base, tiene todas las propiedades de la clase base, se comporta exactamente como la clase base lo hace en la medida visible por el usuario de la misma, y ​​puede usarse en lugar de la clase base en cualquier algoritmo.

  2. Herencia del código. Tiene un fragmento de código en la clase base que desea reutilizar en su clase derivada. La clase base y la clase derivada no tienen que estar relacionadas de ninguna manera, solo quieres reutilizar el código y eso es todo.

La herencia pública en C ++ es la combinación de ambos tipos, obtienes herencia de interfaz y obtienes herencia de código también. La herencia privada es un tipo diferente de bestias, solo se obtiene la herencia del código, los usuarios de su clase derivada no pueden usarla en lugar de la clase base y desde la base de perspectiva del usuario y las clases derivadas no tienen relación alguna.

struct Base {}; struct PublicDerived : public Base {}; struct PrivateDerived: private Base {}; Base * base; PublicDerived * public_derived; PrivateDerived * private_derived; base = public_derived; //good base = private_derived; //compilation error.

Dado que desea cambiar la interfaz, no debe ir con herencia pública, al cambiar la interfaz, efectivamente dice que esas dos clases tienen un comportamiento diferente y no se pueden usar indistintamente. Entonces, lo que realmente quieres es heredar en privado y luego hacer que todos los métodos que quieras sean públicos y no al revés .


Realmente no hay forma de hacer lo que quieres porque si derivas públicamente de Base , un usuario de la clase siempre podrá:

Derived d; Base& b = d; b.bar();

No es "correcto o natural" hacer que las funciones de clase base públicas sean inaccesibles en una clase pública derivada de la clase base; en su lugar, la interfaz de la clase base debe refactorizarse de manera que esas funciones no sean públicas o se dividan en una clase separada.


Si no necesita tratarlo como la clase base más adelante y solo necesita algunas funciones de la clase base, ¿podría usar composición en lugar de herencia? (C # es mi primer idioma, pero entiendes la idea)

class Base { public void foo(); public void bar(); }; class Derived { private Base _base; public void bar() { _base.bar(); } };


con C ++ 11 podrías hacer lo siguiente:

class Base { public: void foo(); void bar(); }; class Derived : public Base { private: using Base::bar; };

Esto garantiza que Base :: bar () no sea accesible desde fuera de la clase Derivada. Por supuesto, todavía es accesible desde fuera de la clase Base.