2016-04-10 10 views
2

Ich habe eine Basis abstrakte Klasse (interface), die über viele DLLs geteilt wird, um von ihm zu erben. Jede DLL hat ein exportiertes Factory-Symbol, das dynamisch ein Objekt erstellt und seinen Zeiger zurückgibt. Was passiert, wenn zwei verschiedene DLLs Klassen mit demselben Namen von derselben abstrakten Klasse geerbt haben?C++ Klasse Kollision über dll

class foo 
{ 
public: 
    virtual void func()const=0; 
}; 

DLL1

class bar: public foo 
{ 
public: 
    virtual void func()const{ 
    std::cout << "From Dll1" << std::endl; 
    } 
}; 

DLL2

class bar: public foo 
{ 
public: 
    virtual void func()const{ 
    std::cout << "From Dll2" << std::endl; 
    } 
}; 

Haupt

int main() 
{ 
    foo* obj1; 
    foo* obj2; 
    // load DLLs 
    // import factory 
    // call factory to initialize objects 
    obj1->func(); // output: "From Dll1" 
    obj2->func(); // output: "From Dll2" 
    return typeid(*obj1) == typeid(*obj2); 
} 

Returns trueobj1 und obj2 Bedeutung sind beide Instan aus der gleichen Klasse. Sowie typeid(*obj1).name() und typeid(*obj2).name() gibt den gleichen Namen class bar zurück. Gibt es eine Möglichkeit, diese Objekte mit RTTI zu unterscheiden, wenn ich DLLs nicht selbst steuern darf? Muss die Klasse einen Mechanismus haben, um ihren für diesen Fall bereitzustellen?

P.S. Wie IInspectable hat gesagt, Sie können Objekt zu seiner Fabrik zuordnen. Aber was ist, wenn die Schnittstelle es ermöglicht, Objekte zu kompilieren? DLL würde niemals zwischen Objekten unterscheiden, die von verschiedenen Modulen zurückgegeben werden, da sie sich nicht über die Fabrik im Klaren sind. Das ist der Hauptgrund, den ich gerne verwenden würde RTTI.

+1

Wenn Sie * "Import Factory" * sagen, müssen Sie das Modul, das es implementiert, bereits auf die eine oder andere Weise bereitstellen. Wenn Sie das Mapping zwischen Funktionszeigern und Modulen nicht speichern möchten, können Sie das Modul jederzeit aus dem Funktionszeiger abrufen, indem Sie [GetModuleHandleEx] (https://msdn.microsoft.com/en-us/library) aufrufen /windows/desktop/ms683200.aspx). – IInspectable

+0

@Intspectable Danke für Ihre Antwort! Ich möchte in der Lage sein, Objekte aus mehreren Modulen zusammenzusetzen. In der abgeleiteten Klassenimplementierung könnten Einschränkungen bestehen, um nur Objekte bestimmter Art zu akzeptieren. – Ivars

+0

Die Verbreitung von CRT-Ressourcen über Modulgrenzen hinweg ist gleichbedeutend mit dem Eintritt in eine Welt der Schmerzen. Es ist etwas, das Sie * richtig * machen können, aber es erfordert intime Kenntnis der Feinheiten und des furchtbaren Fleißes. Weitere Informationen finden Sie unter [Mögliche Fehler beim Übergeben von CRT-Objekten über DLL-Grenzen hinweg] (https://msdn.microsoft.com/de-de/library/ms235460.aspx).Während das alles so aussieht, als würden Sie COM neu erfinden, warum nicht stattdessen das Real Thing ™ verwenden? – IInspectable

Antwort

0

Erstens ist diese Art von Konstrukt nur mit run time dynamically linking of your DLLs möglich. Wenn Sie verwenden würden, würde der Linke die doppelten Symbole in der Importbibliothek identifizieren. So sind wir nicht mehr in dem Standard-C++, aber bei der Umsetzung spezifisches Verhalten:

HINSTANCE dll1Handle = LoadLibraryA("Test0410-1DLL1.dll"); 
HINSTANCE dll2Handle = LoadLibraryA("Test0410-1DLL2.dll"); 
fct f1, f2; 
foo *obj1, *obj2; 

if (dll1Handle == NULL || dll2Handle == NULL) { 
    cout << "Both DLL couldn't be uploaded!" << endl; 
} 
else { 
    f1 = (fct)GetProcAddress(dll1Handle, "myfactory"); 
    f2 = (fct)GetProcAddress(dll2Handle, "myfactory"); 

    if (f1 == NULL || f2 == NULL) { 
     cout << "Both factories couldn't be uploaded!" << endl; 
    } 
    else { 
     obj1 = f1(); 
     obj2 = f2(); 

     obj1->func(); 
     obj2->func(); 

     if (typeid(obj1) == typeid(obj2)) 
      cout << "Same type"<<endl; 
     else cout << "Different type" << endl; 
    } 
} 

Der Code erzeugte durch MSVC herausfindet, dass beide den gleichen Typen haben. Aber nichts sichert dieses Verhalten.

Es ist auch schwierig, die Zeiger der virtuellen Funktion zu nutzen, weil Sie die Adresse obj->func nicht nehmen können, müssen Sie take the address von foo::func, die eine relative Adresse ist und bleibt die gleiche für beide Klassen sein.

Da Ihr Konstrukt an der Grenze der ODR ist und auf implementierungsspezifisches Verhalten aufbaut, denke ich, dass der einfachste Weg, Ihre Klassen sicher zu unterscheiden, eine selbst erstellte virtuelle Typidentifikationsfunktion in foo wäre, die z Beispiel kombinieren Sie die Klasse und den DLL-Namen.