Tengo una clase base abstracta que actúa como interfaz.Herencia múltiple de dos clases derivadas
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 en sí mismo).
Por lo tanto: (mala pseudocódigo)
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
}
En primer lugar, puedo hacer esto? ¿Puedo heredar de dos clases derivadas de la misma base? (Eso espero).
Aquí está el "problema real", aunque (he mentido un poco más arriba para simplificar el ejemplo).
Lo que realmente me he ido y hecho es añadir métodos no abstractos descriptores de acceso 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, un idioma común es hacer que todos los métodos virtuales privadas.
Desafortunadamente, 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 compilación).
De todos modos, g ++ se queja de que: "la solicitud para el miembro init() es ambigua" al intentar 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 de la expresión idiomática de hacer que los métodos virtuales sean privados? - ¿Cómo refactorizo mi código para hacer lo que quiero? (Proporcionar una interfaz común, pero permitir que una manera de intercambiar las implementaciones de "conjuntos" de las funciones miembro)
Editar:
parece que no soy el primero: http://en.wikipedia.org/wiki/Diamond_problem
Parece 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.
¿Por qué dices eso? ¿Cuáles son las implicaciones, aparte de la complejidad de la sintaxis, de la herencia virtual? – mmocny
La conversión de un puntero base a una clase derivada normalmente implica ajustes de puntero, utilizando una tabla de búsqueda dinámica. Esta indirección adicional introduce un costo de conversión de base a derivado. Cuando se llama a un método virtual, esta sobrecarga está en el ruido de la llamada. –