Ich versuche, eine C-Bibliothek in C ++ zu verpacken, um sie zu einer modernen C ++ - Bibliothek auf hohem Niveau und idiomatisch zu machen. Was ich tun möchte, ist, die C-Objekte vollständig undurchsichtig und / oder direkt aus dem C ++ - Code nicht verfügbar zu machen und sie durch höhere Alternativen zu ersetzen oder zu ersetzen.
Das Problem, mit dem ich konfrontiert bin, ist einfach: Ich möchte den C-Header nur in die C ++ - Quelle einfügen, so dass der C ++ - Header, wenn er enthalten ist, auch die C-Header-Deklarationen nicht enthält. t verschmutzen den globalen Namespace.
Aber es sieht so aus, als ob die korrekte Trennung der Header- und Quelldateien es mir nicht erlaubt. Hier ist eine sehr dumifizierte Version meines Problems, die Kommentare werden Ihnen den Rest erzählen:
my_header.h:
%Vor%my_header.hpp:
%Vor%my_source.cpp:
%Vor%Also meine Fragen sind: vermisse ich etwas sehr offensichtlich hier? Ist das überhaupt möglich? Gibt es einen Trick, den ich nicht kenne?
In den Kommentaren der Frage @AnalPhabet wurde sarkastisch vorgeschlagen, dass man #include
eines C verwenden sollte Header in einem namespace
. @nm bestätigte, dass es tatsächlich eine funktionierende Lösung ist, und jetzt habe ich es auf meinem eigenen Setup getestet, und zum Glück ist es das funktioniert ganz gut.
(Obwohl ich keine Ahnung habe, ob dies implementierungsspezifisch ist oder nicht, aber ich habe sowohl g++
als auch clang++
getestet und es funktioniert.)
Es löst nicht das Opakness Problem, aber es macht ein bisschen schwieriger um direkt auf die rohen C Daten zuzugreifen, da es in einem separaten% co_de lebt % jetzt, daher kann der Benutzer nicht versehentlich zugreifen, sondern willig.
Also sollte namespace
wie folgt aussehen:
Wo auch immer my_header.hpp
ist my_header.hpp
'd, der Benutzer kann nur auf die C-Werte wie folgt zugreifen:
Wenn die ganze Idee des Schreibens von High-Level- und idiomatischen C ++ - Wrappern Sicherheit, automatische Speicherverwaltung und bequeme C ++ - Typen wie std::sting
bringt, würde ich C-Header nur in cpp
-Datei einschließen.
Stellen Sie eine saubere idiomatische C ++ - Schnittstelle bereit und verwenden Sie die C-Bibliothek nur in der Implementierung.
Haben Sie keine Angst, ein paar Utility-Funktionen zu schreiben, die C-Daten in C ++ und zurück konvertieren. Wenn eine C ++ - Klasse C-spezifische Daten enthalten soll und es nicht möglich ist, sie durch C ++ - Analog zu ersetzen, verwenden Sie irgendeine Art Löschungstechnik , saubere Schnittstelle zu behalten.
Ich würde mir keine Sorgen über die Leistung aufgrund eines solchen Umbruchs machen, bis ich es oben in einem Profiler-Protokoll sehe. In den meisten Fällen ist es kein Flaschenhals.
Auch hier ist die Trennung von Interface und Implementierung normalerweise ein Gewinn.
AKTUALISIEREN
Anfangs dachte ich eher an eine projektspezifische C ++ - Schnittstelle als an einen universellen C ++ - Wrapper in der C-Bibliothek.
Lösung mit extern "C"
in einem Namespace verpackt sieht für mich richtig aus (siehe § 7.5 des C ++ 11 Standards). Aber ich habe diese Technik noch nie in freier Wildbahn gesehen.
Sie können weiter gehen und verschachtelten detail
-Namespace hinzufügen, um my
namespace nicht mit C-Typen zu verschmutzen. Dieser Trick ist in Header-Bibliotheken beliebt:
Beachten Sie, dass Sie C-Funktionen nicht vollständig undurchsichtig machen oder sie in einen einzelnen Namespace einschließen können, wenn Sie mit der statischen Bibliothek verknüpfen. Sie haben eine externe Verbindung und wissen nichts über Namensräume.
%Vor%Grundsätzlich beziehen sich alle diese Deklarationen auf die gleiche C-Funktion. Da C keine Namespaces und kein Überladen unterstützt, verwendet Linker normalerweise Funktionsnamen als eindeutige Bezeichner (selbst Argumenttypen werden ignoriert).
Wie auch immer, dieser Ansatz wird dazu beitragen, einen versehentlichen Zugriff auf die C-Schnittstelle zu vermeiden.
Ich bin mir nicht sicher, ob es legal ist, aber ich denke, dass extern "C"
nur dazu da ist, Funktionen zu entmangeln, so lange Sie sie in der .cpp-Datei behalten, können Sie damit durchkommen.
Das ist ein wenig profan, aber es scheint mit gcc 4.3.5 zu funktionieren. Es zeigt, dass Sie C-Funktionen verwenden können, während Sie sie auch in einem Namespace verstecken.
Ich habe mich nicht damit beschäftigt, struct_t zu erben, aber es sollte wahrscheinlich funktionieren. Ich habe keine Ahnung, ob du die enum class
abziehen kannst.
foo.h
%Vor%foo.c
%Vor%bar.hpp
%Vor%bar.cpp
%Vor%driver.cpp
%Vor%Demo ...
%Vor%Tags und Links c++ namespaces c++11 header wrapper