9

Estoy teniendo un momento difícil con un temido problema de diamantes. Para un recordatorio, aquí es la jerarquía de clases clásica de este problema:Herencia virtual y temido diamante

B 
/\ 
C1 C2 
    \/
    D 

Para solucionarlo, la solución estándar es hacer C1 y C2 utilizan la herencia virtual para heredar a partir de B.

Mi problema es que B y C1 son de un SDK que no puedo modificar. Ejemplo a continuación donde no puedo hacer SubClassB hereda virtualmente desde Base. Clases: PureVirtualBase, Base y SubClassB son del SDK que uso. No puedo modificarlos. SubClassA y Leaf son mis clases personalizadas. Puedo cambiarlos

 PureVirtualBase(SDK) 
      | 
     Base(SDK) 
    /  \ 
SubClassA SubClassB(SDK) 
     \  /
      Leaf 

En tal situación, donde SubClassB no se puede cambiar a utilizar la herencia virtual desde Base. ¿Cómo lo debe de manera que:

  • Hoja ejemplo sólo contiene una Base
  • Evitar la ambigüedad cuando se trata de funciones de acceso definido puro virtual en PureVirtualBase e implementado en Base
class PureVirtualBase 
{ 
public: 
    PureVirtualBase() 
    { 
     cout<<"<<PureVirtualBase::PureVirtualBase" << endl; 
     cout<<">>PureVirtualBase::PureVirtualBase" << endl; 
    } 
    virtual int f_PureVirtualBase()=0; 
}; 
class Base : public PureVirtualBase 
{ 
public: 
    Base(std::string id) { 
     cout<<"<<Base::Base:"<<id << endl; 
     m_id=id; 
     cout<<">>Base::Base:"<<m_id << endl; 
    } 
    virtual int f_PureVirtualBase() { 
     cout<<"Base::f_PureVirtualBase" << endl; 
     return 1; 
    } 
private: 
    std::string m_id; 
}; 
class SubClassA: public virtual Base 
{ 
public: 
    SubClassA(): Base("From SubClassA") { 
     cout<<"<<SubClassA::SubClassA" << endl; 
     cout<<">>SubClassA::SubClassA" << endl; 
    } 
}; 
class SubClassB: public Base 
{ 
public: 
    SubClassB():Base("From SubClassB") { 
     cout<<"<<SubClassB::SubClassB" << endl; 
     cout<<">>SubClassB::SubClassB" << endl; 
    } 
};  
class Leaf: public SubClassA, public SubClassB 
{ 
public: 
    Leaf():SubClassA(), SubClassB(), Base("From Leaf") { 
     cout << "<<Leaf::Leaf" << endl; 
     cout << ">>Leaf::Leaf"<< endl; 
    } 
}; 
int main(int argc, char *argv[]) 
{ 
    QCoreApplication a(argc, argv); 
    Leaf myleaf; 
    myleaf.f_PureVirtualBase(); 
    return a.exec(); 
} 
  • Si comentar la llamada a f_PurevirtualBase compila pero tengo una advertencia que base virtual 'Base' inaccesible 'hoja' debido a la ambigüedad Si descomentar esta llamada: Me sale este error: solicitud de miembro de ' f_PureVirtualBase' es ambiguo
  • Si preceden a este llamado por el nombre de la clase (myleaf.SubClassA :: f_PureVirtualBase() entonces funciona, pero algo es obviamente erróneo, ya que hay 2 Base contenida en la Hoja Objeto).

¿Alguna pista?

Más información para responder a los comentarios

Mi arquitectura objetivo es un poco más compleja que la muestra que he proporcionado en la pregunta original:

PureVirtualBase(SDK) 
     | 
    Base(SDK) 
     | 
     --SubClassA 
     --SubClassB(SDK) 
     --SubClassC(SDK) 
     --SubClassD(SDK) 

LeafOne: hereda de SubClassA y SubClassB (SDK)

LeafTwo: hereda de SubClassA y SubClassC (SDK)

LeafThree: hereda de SubClassA y SubClassD (SDK)

SubClassA es mi propio código privado. Proporciona funciones personalizadas. Debería poder tratarse como una instancia Base por métodos SDK. No se creará una instancia de esta clase pero está aquí para poder manejar LeafOne, LeafTwo y LeafThree en la misma cuando se realiza algún tratamiento.

+6

¿Qué tal una clase heredada y otra compuesta? – iammilind

+2

Es algo que estoy considerando, pero la integración de una Leaf Class tal no sería tan elegante en nuestro SDK y muchos problemas diferentes deberán resolverse. Aún tienes razón, es una manera de resolver este problema, pero me gustaría encontrar una manera de hacerlo a través de la herencia para una integración más fácil con las características del SDK. – Marc

+0

¿Por qué crees que 'SubClassA' necesita heredar de' Base' en absoluto? Dada la definición de 'SubClassB' es obvio que' Base' no está diseñado para ser una clase base virtual en una jerarquía que incluye 'SubClassB'. –

Respuesta

4

Esto indica un problema con su diseño, por lo que la respuesta más simple es para evitar el diamante en primer lugar. Su elección de nombres para el código de ejemplo es lo suficientemente grave como para hacer que sea difícil razonar sobre lo que realmente podría querer hacer, pero en cualquier caso reconsidere si necesita para heredar de ambos padres, y si eso tiene sentido.

La herencia es una de las construcciones más abusadas que hay en los lenguajes OO, resuelve un problema, pero se usa como un golden hammer en cualquier otro lugar. Muchas veces lo que tienes en la mano es un screw, no es un clavo y la herramienta correcta no es un martillo.

+0

Creo que acaba de llegar al punto. al final utilicé su consejo y cambié nuestra jerarquía de clases. – Marc

+0

Usted dijo este martillo + broma también ayer, ¿no es así? p? – Liviu

1

Si realmente está atascado con estas restricciones de diseño, definitivamente buscaría subclases de B directamente con una clase que tomara C1 y C2 como componentes compuestos. Lamentablemente, esto requiere una duplicación manual de su interfaz (ojalá sea pequeña o puede limitarla a lo que necesita) y un seguimiento a través de los subcomponentes. No es bonito, pero a menos que puedas imponer algunas concesiones sobre el diseño en otra parte, entonces no te queda mucha opción.

Una desventaja, por supuesto, es que no tiene la identidad de tipo que está buscando (la subclase no satisfará "isa" de C1 o C2) que puede ser suficiente para volar este enfoque fuera del agua .

No es bonito. Pero espero que, dadas tus limitaciones, podría ser la solución "menos mala".

Cuestiones relacionadas