Frage

Ich habe eine Klasse mit Geräte 2 Schnittstellen und erbt 1-Klasse. Also, in der Regel sieht es wie folgt aus:

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

Es gibt einen Punkt im Code, wo ich eine IB * haben, aber könnte wirklich eine A * verwenden. Ich hatte gehofft, dass eine dynamische Umwandlung möchte dies:

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

leider funktioniert das nicht. Gibt es eine richtige Art und Weise, dies zu tun? Oder sollte ich eine Arbeit um implementieren? Ich habe beide darüber, dass sie dachte IB und IC erben praktisch von A, aber IIRC letzte Mal habe ich versucht, dass es einige Komplikationen, die es nicht wünschenswert gemacht.

Alle Gedanken?

Bearbeiten : oh ja, das Teil eines Plugin-API ist, so leider habe ich keinen direkten Zugriff auf die T Art, wo ich die A * benötigen. Mein Beispiel hat dann nebeneinander, aber wie gesagt, es ist komplizierter. Im Prinzip habe ich 2 gemeinsam genutzte Bibliotheken. T und T1 (wo ich eine IB * haben) sind beide Klassen, die eine Plugin-API und sind intern auf die gemeinsam genutzten Bibliotheken implementieren.

Zur Klarstellung: Hier ist ein spezifischeres Beispiel für meine typischen Plugins (sie sind in separaten Bibliotheken):

Plugin A:

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

Plugin 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.
};

Bearbeiten : Ich habe eine Vermutung, dass das Problem ist, dass pluginA und pluginB in anderen freigegebenen Bibliotheken ist. Vielleicht ist die rtti kreuzen nicht Modulgrenzen. Ich denke, das könnte der Fall sein, weil die Menschen die Beispiele scheinen in meinen Tests gut zu funktionieren. Insbesondere hat pluginB keine „Typeinfo für PluginA“ wenn ich eine „nm“ auf es tun. Dies kann der Kern des Problems sein. Wenn dies der Fall ist, werde ich einfach um ihn herum haben entweder virtuelle Vererbung arbeiten oder eine virtuelle cast_to_qobject() Funktion in einer meiner Schnittstellen.

War es hilfreich?

Lösung 4

Habe ich es endlich, Daniel Paull richtig war, dass eine „Seitwärts dybnamic_cast“erlaubt werden soll. Mein Problem war, weil mein Code gemeinsam genutzte Bibliotheken beteiligt sind. Die Typeinfo von PluginA war in PluginB nicht zur Verfügung. Meine Lösung war effektiv RTLD_NOW und RTLD_GLOBAL meinen Ladevorgang hinzufügen

technisch war es

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

, weil ich Qt-Plugin-System, aber gleichen Unterschied bin mit. Diese Flags zwingen, alle Symbole aus geladenen Bibliotheken sofort gelöst zu werden und zu anderen Bibliotheken sichtbar sein. Daher macht die Typeinfo allen zur Verfügung, die es benötigt. Die dynamic_cast arbeitete wie erwartet, sobald diese Fahnen an Ort und Stelle waren.

Andere Tipps

Hat jede Klasse mindestens eine virtuelle Methode? Wenn nicht, ist es Ihr Problem. überwinden sollte das Problem einen virtuellen Destruktor jede Klasse hinzufügen.

Die folgende glücklich für mich gearbeitet:

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;
}

EDIT:

Nach all den neuen Informationen, und das ungewöhnliche Verhalten (Code sollte einfach funktionieren!), Hat die folgende Hilfe? Ich habe eine Schnittstelle namens IObject und verwendet virtuelle Vererbung, um sicherzustellen, eingeführt, dass es nur eine Kopie dieser Basisklasse ist. Können Sie jetzt auf IObject gegossen und dann auf 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;
}

Ich schlage nicht vor, dass es die richtige Lösung ist, aber es könnte ein paar Informationen bieten, was los ist ...

  

Gibt es eine richtige Art und Weise, dies zu tun? Oder sollte ich eine Arbeit um implementieren? Ich habe beide darüber, dass dachte IB und IC praktisch von A erben, aber IIRC letzte Mal habe ich versucht, dass es einige Komplikationen, die es nicht wünschenswert gemacht.

Ich nehme es dann, dass die Definitionen von IB und IC unter Ihrer Kontrolle sind.

Es ist die Art und Weise, in der COM-Schnittstellen unter Windows arbeiten; diese tun, was Sie wollen, tun wollen, das heißt:.

  • Guss von einer Schnittstelle zur anderen
  • Die Implementierung ist undurchsichtig für den Anrufer
  • Nur die Umsetzung weiß, welche Schnittstellen es implementiert

das Sie tun, Sie können wie etwas tun (ungetestet Code voraus) ...

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;
}

Eine viel einfachere, hartcodierte Version dieser wäre:

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

Die Besetzung mit einem T * ersten dann zu A:

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

Wenn IB im Allgemeinen sollte Gießbare sein, dann vielleicht sollte IB von A erbt.

Edit: Ich dies gerade versucht, und es funktioniert -. Beachten Sie, dass E zum Zeitpunkt der Erstellung der Hauptmethode ist unbekannt

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(); }

Ich habe auch vor kurzem mit der gleichen Art von Problem betroffen belästigt. Weitere Informationen finden Sie GCC FAQ-Eintrag:

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

Neben mit RTLD_ * Fahnen anweist dlopen, einige Verkörperungen dieses Problem kann auch durch den Linker gelöst werden, siehe seine -E und -Bsymbolic Optionen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top