Herencia múltiple de dos clases derivadas

Tengo una clase base abstracta que actúa como interfaz.

Tengo dos “conjuntos” de clases derivadas, que implementan la mitad de la clase abstracta. (un “conjunto” define los métodos virtuales abstractos relacionados con la inicialización, el otro “conjunto” define aquellos relacionados con el “trabajo” real).

Luego obtuve clases que usan herencia múltiple para construir clases completamente definidas (y no agrega nada).

Entonces: (pseudocódigo malo)

class AbsBase { virtual void init() = 0; virtual void work() = 0; } class AbsInit : public AbsBase { void init() { do_this(); } // work() still abs } class AbsWork : public AbsBase { void work() { do_this(); } // init() still abs } class NotAbsTotal : public AbsInit, public AbsWork { // Nothing, both should be defined } 

Antes que nada, ¿puedo hacer esto? ¿Puedo heredar de dos clases derivadas de la misma base? (Eso espero).

Aquí está el “problema real”, sin embargo (mentí un poco arriba para simplificar el ejemplo).

Lo que realmente he hecho y hecho es agregar métodos de acceso no abstractos a la clase base:

 class AbsBase { public: void init() { init_impl(); } void work() { work_impl(); } private: virtual void init_impl() = 0; virtual void work_impl() = 0; } 

Porque, una expresión común es hacer que todos los métodos virtuales sean privados.

Lamentablemente, ahora AbsInit y AbsWork heredan estos métodos, por lo que NotAbsTotal hereda “dos de cada uno” (me doy cuenta de que puedo estar matando lo que realmente está sucediendo en el momento de la comstackción).

De todos modos, g ++ se queja de que: “la solicitud de miembro init () es ambigua” cuando se intenta usar la clase.

Supongo que, si hubiera usado mi clase AbsBase como una interfaz pura, esto se habría evitado (suponiendo que el ejemplo superior sea válido).

Entonces: – ¿Estoy muy lejos con mi implementación? – ¿Es esto una limitación del lenguaje de hacer que los métodos virtuales sean privados? – ¿Cómo refactorizo ​​mi código para hacer lo que quiero? (Proporcione una interfaz común, pero permita una forma de cambiar implementaciones para “conjuntos” de funciones de miembros)

Editar:

Parece que no soy el primero: http://en.wikipedia.org/wiki/Diamond_problem

Parece que la herencia virtual es la solución aquí. He oído hablar de herencia virtual antes, pero no me he acostumbrado a eso. Todavía estoy abierto a sugerencias.

Parece que quieres hacer herencia virtual. Si eso resulta ser realmente una buena idea es otra pregunta, pero así es como lo haces:

 class AbsBase {...}; class AbsInit: public virtual AbsBase {...}; class AbsWork: public virtual AbsBase {...}; class NotAbsTotal: public AbsInit, public AbsWork {...}; 

Básicamente, la herencia múltiple no virtual predeterminada incluirá una copia de cada clase base en la clase derivada e incluye todos sus métodos. Esta es la razón por la que tiene dos copias de AbsBase, y la razón por la que el uso de su método es ambiguo es porque ambos conjuntos de métodos están cargados, ¡así que C ++ no tiene manera de saber a qué copia acceder!

La herencia virtual condensa todas las referencias a una clase base virtual en una estructura de datos. Esto debería hacer que los métodos de la clase base no sean ambiguos nuevamente. Sin embargo, tenga en cuenta: si hay datos adicionales en las dos clases intermedias, puede haber una pequeña sobrecarga de tiempo de ejecución adicional para permitir que el código encuentre la clase base virtual compartida.

Debes declarar la herencia como virtual:

 struct AbsBase { virtual void init() = 0; virtual void work() = 0; }; struct AbsInit : virtual public AbsBase { void init() { } }; struct AbsWork : virtual public AbsBase { void work() { } }; struct NotAbsTotal : virtual public AbsInit, virtual public AbsWork { }; void f(NotAbsTotal *p) { p->init(); } NotAbsTotal x; 

Se puede hacer, aunque da la mayoría de los escalofríos.

Necesita usar “herencia virtual”, cuya syntax es algo así como

 class AbsInit: public virtual AbsBase {...}; class AbsWork: public virtual AbsBase {...}; class NotAbsTotal: public AbsInit, public AbsWork {...}; 

Luego debe especificar qué función desea usar:

 NotAbsTotal::work() { AbsInit::work_impl(); } 

(ACTUALIZADO con la syntax correcta)

Tienes que empezar a pensar en los términos de lo que estás tratando de modelar aquí.

La herencia pública solo debe usarse para modelar una relación “isa”, por ejemplo, un perro es un animal, un cuadrado es una forma, etc.

Eche un vistazo al libro de Scott Meyer, Effective C ++, para obtener un excelente ensayo sobre cómo deben interpretarse los diversos aspectos del diseño OO.

Editar: Olvidé decir que aunque las respuestas proporcionadas hasta ahora son técnicamente correctas, no creo que ninguna de ellas aborde los problemas de lo que está tratando de modelar y ese es el quid de su problema.

HTH

aclamaciones,

Robar

Encontré un ejemplo bueno y simple en el siguiente enlace. El artículo explica con un progtwig de ejemplo para calcular el área y el perímetro de un rectángulo. Puedes verificarlo … cheques

La herencia multinivel es una jerarquía de herencia en la que una clase derivada hereda de múltiples clases base. Lee mas..

http://www.mobihackman.in/2013/09/multiple-inheritance-example.html