static_cast reinterpret_cast ejemplo dynamic_cast dev c++ casting dynamic-cast

c++ - reinterpret_cast - lanzamiento dinámico con interfaces



dynamic_cast c++ ejemplo (5)

¿Hay una forma adecuada de hacer esto? ¿O debería implementar un trabajo completo? He pensado en heredar virtualmente IB y CI de A, pero la última vez que intenté IIRC probé que había algunas complicaciones que lo hicieron indeseable.

Considero que las definiciones de IB e IC están bajo su control.

Existe la manera en que las interfaces COM funcionan en Windows; estos hacen lo que quieren hacer, es decir:

  • Transmitir de una interfaz a otra
  • La implementación es opaca para quien llama
  • Solo la implementación sabe qué interfaces implementa

Haz esto, puedes hacer algo como (código no probado por adelantado) ...

interface IQueryInterface { IQueryInterface* queryInterface(const Guid* interfaceId); }; interface IB : public abstract IQueryInterface { ... }; interface IC : public abstract IQueryInterface { ... }; //within your implementation class IQueryInterface* T::queryInterface(const Guid* interfaceId) { if (matches(interfaceId,GUID_IB)) return (IB*)this; if (matches(interfaceId,GUID_IC)) return (IC*)this; if (matches(interfaceId,GUID_A)) return (A*)this; return 0; }

Una versión mucho más simple y más codificada de esto sería:

class A; //forward reference interface IB { virtual A* castToA() { return 0; } }; class T : public A, IB, IC { virtual A* castToA() { return this; } };

Tengo una clase con implementa 2 interfaces y hereda 1 clase. Entonces, generalmente se ve así:

class T : public A, public IB, public IC { };

Hay un punto en el código donde tengo un IB * , pero realmente podría usar un A * . Tenía la esperanza de que un elenco dinámico quisiera esto:

IB *b_ptr = new T; // it''s really more complicated, but serves the example A *a_ptr = dynamic_cast<A *>(b_ptr);

desafortunadamente, esto no funciona. ¿Hay una forma adecuada de hacer esto? ¿O debería implementar un trabajo completo? He pensado en heredar virtualmente IB y IC de A , pero la última vez que intenté IIRC probé que había algunas complicaciones que lo hicieron indeseable.

¿Alguna idea?

EDITAR : oh sí, esto es parte de un API de complemento, así que desafortunadamente no tengo acceso directo al tipo T donde necesito el A * . Mi ejemplo tiene uno al lado del otro, pero como se mencionó, es más complicado. Básicamente tengo 2 bibliotecas compartidas. T y T1 (donde tengo un IB * ) son ambas clases que implementan una API de complemento y son internas a las bibliotecas compartidas.

Para aclarar: este es un ejemplo más específico de mis complementos típicos (están en bibliotecas separadas):

plugin A:

class PluginA : public QObject, public PluginInterface, public OtherInterface { };

complemento B:

class PluginB : public QObject, public PluginInterface { // in here, I have a PluginInterface *, but really could use a QObject * // unfortunately, PluginB has absolutely no knowledge of the "PluginA" type // it just so happens that my PluginInterface * pointer points to an object of type // PluginA. };

EDIT : Supongo que el problema es que pluginA y pluginB están en diferentes bibliotecas compartidas. Quizás el rtti no cruce los límites del módulo. Creo que este podría ser el caso porque los ejemplos de las personas parecen funcionar bien en mis pruebas. Específicamente, pluginB no tiene "typeinfo for PluginA" si hago un "nm" en él. Este puede ser el núcleo del problema. Si este es el caso, simplemente tendré que cast_to_qobject() ya sea por herencia virtual o por una función virtual cast_to_qobject() en una de mis interfaces.


¿Cada clase tiene al menos un método virtual? Si no, ahí está tu problema. Agregar un destructor virtual a cada clase debería superar el problema.

Lo siguiente felizmente funcionó para mí:

class IC { public: virtual ~IC() {} }; class IB { public: virtual ~IB() {} }; class A { public: virtual ~A() {} void foo() { /* stick a breakpoint here to confirm that this is called */ } }; class T : public A, public IB, public IC { public: virtual ~T() {} }; int main(void) { IB *b_ptr = new T; A *a_ptr = dynamic_cast<A *>(b_ptr); a_ptr->foo(); return 0; }

EDITAR:

Después de toda la información nueva y el comportamiento inusual (¡su código debería funcionar!), ¿Le ayuda lo siguiente? Introduje una interfaz llamada IObject y uso la herencia virtual para garantizar que solo haya una copia de esta clase base. ¿Puedes ahora lanzar a IObject y luego a A?

class IObject { public: virtual ~IObject() {} }; class IC : virtual public IObject { public: virtual ~IC() {} }; class IB : virtual public IObject { public: virtual ~IB() {} }; class A : virtual public IObject { public: virtual ~A() {} void foo() { /* stick a breakpoint here to confirm that this is called */ } }; class T : virtual public A, virtual public IB, virtual public IC { public: virtual ~T() {} }; int main() { IB *b_ptr = new T; A *a_ptr = dynamic_cast<A *>( dynamic_cast<IObject *>(b_ptr) ); a_ptr->foo(); return 0; }

No estoy sugiriendo que sea la solución correcta, pero podría ofrecer información sobre lo que está pasando ...


Transmitir a T * primero y luego a A:

IB *b_ptr = new T; // it''s really more complicated, but serves the example A *a_ptr = dynamic_cast<T *>(b_ptr);

Si IB en general debería ser moldeable a A, entonces quizás IB debería heredar de A.

Editar: Acabo de probar esto y funciona - tenga en cuenta que E es desconocido en el momento de compilar el método principal.

struct A { virtual ~A() {} }; struct C { virtual ~C() {} }; A* GetA(); int main() { C *y = dynamic_cast<C *>(GetA()); if (y == NULL) cout << "Fail!"; else cout << "Ok!"; } struct E : public A, public C { }; A* GetA() { return new E(); }


Recientemente también me he molestado con el mismo tipo de problema. Para obtener más información, consulte la entrada de preguntas frecuentes de GCC:

http://gcc.gnu.org/faq.html#dso

Además de instruir a dlopen con indicadores RTLD_ *, el engarce también puede resolver algunas encarnaciones de este problema, vea sus opciones -E y -Bsymbolic.


Finalmente lo descubrí, Daniel Paull estaba en lo correcto en cuanto a que se debe permitir una " dybnamic_cast lateral". Mi problema fue porque mi código está involucrando bibliotecas compartidas. El tipo de información de PluginA no estaba disponible en PluginB. Mi solución fue agregar efectivamente RTLD_NOW y RTLD_GLOBAL a mi proceso de carga

técnicamente era

loader.setLoadHints(QLibrary::ResolveAllSymbolsHint | QLibrary::ExportExternalSymbolsHint);

porque estoy usando el sistema de plugin de Qt pero con la misma diferencia. Estos indicadores obligan a que todos los símbolos de las bibliotecas cargadas se resuelvan de inmediato y sean visibles para otras bibliotecas. Por lo tanto, el typeinfo está disponible para todos los que lo necesiten. El dynamic_cast funcionó como se esperaba una vez que estas banderas estuvieron en su lugar.