2016-03-28 7 views
2

Ich verpacke eine C++ - Bibliothek, indem ich eine C-Schnittstelle schreibe. Aus diesem Grund habe ich eine C-Header-Datei erstellt, in der die meisten Funktionen void* anstelle von C++ - Klassenzeigern zurückgeben/akzeptieren.Umwandlung in void * und typedefs in C++

Ich weiß, dass gefährlich aus zu werfen/void * in C++, siehe Casting to void* and Back to Original_Data_Type*

Derzeit mit Vererbung Ich bin immer auf die Basisklasse eines Objekts Gießen vor *

void* temp = static_cast<BaseClass*>(ptr) 
nichtig Zuordnung

und zurück

BaseClass* base = static_cast<BaseClass*>(voidPtr) 
DerivedClass* derived = dynamic_cast<DerivedClass*>(base) 

jedoch void* in einer Header-Dateien unter Verwendung entfernen Semantik und c machen Komplexe Funktionen schwer zu lesen. Zum Beispiel:

void myComplexFunc(void* index, void* data, void* somethingElse) 

Für diese Milderung ich wollte typedefs verwenden, auch wenn sie irgendeine Art Sicherheit zumindest sie einen Einblick geben für den Leser nicht geben. den vorherigen Schnipsel Vergleichen mit diesem

extern "C" 
{ 
... 
typedef void Index; 
typedef void DBRecord; 
typedef void DBResult; 
void myComplexFunc(Index* index, DBRecord* data, DBResult* somethingElse) 
... 
} 

Grundsätzlich sind diese typedefs als eine Art zur Dokumentation dienen, wenn mehrere void* als Parameter einer Funktion verwendet werden (Beachten Sie, dass ich mehrere C++ Klassen mit jeweils 10 Methoden bin Einwickeln , also gibt es viele Funktionen, die eine Lücke * als ersten Parameter enthalten.

Aus diesem Grunde i

extern "C" // In.h file (declaration) 
{ 
typedef void Index; 
... 
Index* getIndex(); 
void modifyIndex(Index* index); 
... 
// In .cpp file (definition) 
Index* getIndex() { 
    DerivedCppIndex* derived = ... 
    BaseCppIndex* base = static_cast<BaseCppIndex*>(derived) 
    return base; 
} 
... 
void modifyIndex(Index* index) { 
    BaseCppIndex* base = static_cast<BaseCppIndex*>(index); 
    DerivedCppIndex* derived = dynamic_cast<DerivedCppIndex*>(base); 
    ... 
} 

Ist die Verwendung eines typedef statt Leere typedefs verwenden wollte * bewirkt, dass alle Mühe, die Fragen der Zuordnung in Bezug auf void *?

+0

Gibt es einen Grund, warum Sie das tun? Es scheint eine super schlechte Idee zu sein. – tadman

+0

Ich denke (nachdem ich meine Antwort geschrieben habe), dass er seine Typhierarchie dem Benutzer nicht offen legen will; Während also aus seinem Code "DerivedIndex" in "Index" umwandelbar ist, wird es nicht funktionieren, wenn alles, was gesehen wird, "Klasse Index" ist; Klasse DerivedIndex'. –

+1

klingt wie ein x-y-Problem, bitte stellen Sie einige Anwendungsfälle und Hintergrund zur Verfügung. – user3528438

Antwort

2

Es sollte keine Probleme verursachen, aber es wird nur API-Benutzern ein falsches Gefühl der Sicherheit geben (da jeder beliebige Zeiger auch funktioniert). Es gibt nichts, die Compiler beschweren zu verhindern, wenn Sie etwas tun:

int i; 
// .... 
modifyIndex(&i); 

So, während Sie keine Probleme haben, werden Sie keine Kompilierung-Kontrollen und Vollstreckungen haben entweder.

Beachten Sie, dass Sie die Klasse einfach deklarieren können, ohne sie zu definieren.

Der richtige Weg, um das void-pointer "Problem" zu lösen (und es ist nicht wirklich ein Problem, es ist nur ein Aspekt von C (und damit C++), die Code schwierig pflegen, ohne die richtige Pflege/Dokumentation) ist irgendwie zu offenbaren Index als ein undurchsichtiger Typ; z.B.

+0

Ich stimme dir zu, aber mein Anwendungsfall ist eine C-Bibliothek, so dass ich nicht Klasse in meiner öffentlichen Header-Datei verwenden kann (und das ist der Grund für die Verwendung void *) –

+0

Sie können immer noch ein Dummy-Struktur, wenn sie unter C ausgeführt wird, zum Beispiel: '#ifndef __cplusplus typedef struct IndexCDummy Index'. Ich habe diesen Ansatz in der Vergangenheit genutzt - er gewährleistet die Sicherheit des Benutzers. In diesem Fall wird "IndexCDummy" niemals irgendwo definiert, aber es macht den Compiler auf diesen getippten opaken Zeiger aufmerksam. Ich würde dies in meine Antwort aufnehmen, aber es würde die Antwort wesentlich anders machen als es steht –

0

Erstellen eines typedef für void ist ein bisschen peinlich. Üblicher ist es, void* als IndexHandle zu definieren und Clients Ihres Codes zu zwingen, einen Wert des undurchsichtigen Handle-Typs zu lesen oder als Parameter zu übergeben. Alle Castings sollten innerhalb Ihres Codes stattfinden.