2010-05-25 8 views
5

Estoy tratando de refactorizar algunos códigos mientras dejo la funcionalidad existente intacta. Tengo problemas para lanzar un puntero a un objeto en una interfaz base y luego obtener la clase derivada más tarde. El programa usa un objeto de fábrica para crear instancias de estos objetos en ciertos casos.No se puede lanzar una clase con herencia múltiple

Aquí hay algunos ejemplos de las clases con las que estoy trabajando.

// This is the one I'm working with now that is causing all the trouble. 
// Some, but not all methods in NewAbstract and OldAbstract overlap, so I 
// used virtual inheritance. 
class MyObject : virtual public NewAbstract, virtual public OldAbstract { ... } 

// This is what it looked like before 
class MyObject : public OldAbstract { ... } 

// This is an example of most other classes that use the base interface 
class NormalObject : public ISerializable 

// The two abstract classes. They inherit from the same object. 
class NewAbstract : public ISerializable { ... } 
class OldAbstract : public ISerializable { ... } 

// A factory object used to create instances of ISerializable objects. 
template<class T> class Factory 
{ 
public: 
    ... 
    virtual ISerializable* createObject() const 
    { 
     return static_cast<ISerializable*>(new T()); // current factory code 
    } 
    ... 
} 

This question tiene buena información sobre lo que los diferentes tipos de fundición hacen, pero no ayuda a averiguar esta situación. Usando static_cast y casting regular me da error C2594: 'static_cast': ambiguous conversions from 'MyObject *' to 'ISerializable *'. El uso de dynamic_cast hace que createObject() devuelva NULL. Las clases de estilo NormalObject y la versión anterior de MyObject funcionan con la static_cast existente en la fábrica.

¿Hay alguna manera de hacer que este elenco funcione? Parece que debería ser posible.

Respuesta

10

Tienes que prácticamente heredar de ISerializable (Acabo de probarlo con VS2010). Este es un problema común llamado Diamante problema, donde el compilador no sabe qué ruta de jerarquía tomar.

EDIT:

Esto debe hacerlo:

class NewAbstract : public virtual ISerializable { ... } 
class OldAbstract : public virtual ISerializable { ... } 
+0

+1: Esto funcionó en gcc también. – Troubadour

+3

Exactamente la solución recomendada por las preguntas frecuentes: http://www.parashift.com/c++faq-lite/multiple-inheritance.html#faq-25.8 –

+0

Esto lo resolvió.No me di cuenta de que los resúmenes eran los que necesitaban heredar virtualmente. @Mark Ransom, gracias por el gran enlace. Toda esa página es muy útil. –

-2

Busque "diamante temido" y herencia virtual. Ellos pueden ayudarte.

+0

Hubiera dado un +1 si incluía un enlace. –

+2

Las respuestas aquí no deberían consistir únicamente en dar una respuesta exacta para una pregunta específica, sino en darle al anunciante una orientación para buscar la respuesta, de modo que luego aprenda más y pueda contestar por sí mismo la próxima vez. ¿Por qué proporcionar un enlace cuando hay tantos que podrían ser útiles? Tal vez algo como esto: http://tinyurl.com/2cermbg? Parece algo sin sentido grosero y superfluo. –

+0

Lástima que no pueda publicar enlaces lmtgfy directamente aquí. ;) –

0

No hereda prácticamente de NewAbstract y OldAbstract. Elija uno para heredar virtualmente de. Creo que eso puede encargarse.

+2

No hereda virtualmente de ninguno de ellos; deben heredar virtualmente de la clase base común ('ISerialiazable'). –

1

Usted puede obtener alrededor de ella echando a una de sus bases inmediatos primer ejemplo.

virtual ISerializable* createObject() const 
{ 
    NewAbstract*const na = dynamic_cast< NewAbstract* >(new T()); 
    return dynamic_cast< ISerializable* >(na); 
} 
+0

Parece que esto podría funcionar. Aunque por otras cosas que he leído aquí, parece que tienes que ser muy cuidadoso con esto, dependiendo de las bases. En cualquier caso, para este tema en particular, NewAbstract no es algo que el objeto de fábrica deba conocer. –

+0

@Jay: Sí, cuando vi la respuesta de @ Simon me di cuenta de que eso era lo correcto. Me perdí el hecho de que la herencia virtual estaba en el lugar equivocado. No me gusta borrar una respuesta, incluso si es basura, así que la dejé aquí para languidecer ...;) – Troubadour

Cuestiones relacionadas