Header-Datei plattformunabhängig und standardkonform halten



  • Was mache ich, wenn ich eine Klasse habe, die nach außen hin plattformunabhängig und standardkonform sein soll, intern aber plattformspezifische Funktionalitäten hat? Leider werden ja auch private Attribute und Methoden in der Header-Datei deklariert.
    Ein Beispiel: Ich möchte eine Wrapperklasse für eine Bitmap erstellen, die man, was die Funktionen nach außen angeht, plattformunabhängig benutzen kann. Intern werden die Funktionen dann je nach Betriebssystem spezifisch implementiert. Aber die Klassendeklaration nach außen bleibt eben dieselbe.
    Nun wird eine Bitmap in Windows als Handle gespeichert, ich würde also eine private Membervariable vom Typ HBITMAP haben. Unter einem anderen Betriebssystem bzw. unter einem anderen GUI-Framework bräuchte ich dann eine Variable von einem anderen Typ.
    Ist es irgendwie möglich, für alle Varianten dieselbe Headerdatei zu nehmen oder muß ich auch diese bei jeder Implementierung ändern?
    In C# gibt es das Prinzip der partiellen Klassen. Das fände ich hier auch ganz sinnvoll. Man würde einfach das ganze public- und protected-Zeug in die eigentliche Headerdatei packen und dann für private Sachen eine weitere Headerdatei, die dann genauso implementierungsspezifisch ist wie die CPP-Datei. Doch die haupt-Header-Datei wäre eben immer dieselbe.
    Aber in C++ gibt es leider keine partiellen Klassen. Deshalb würde ich gerne wissen, wie die allgemeine Praxis ist, wenn man eine Klasse hat, bei der die Klassendeklaration plattformneutral soll. Liefert man zu jeder Implementierung trotzdem eine neue Header-Datei aus, wo dann die privaten Attribute und Methoden plattformspezifisch deklariert sind? Oder benutzt man dieses Konstrukt:

    private:
    #ifdef WIN32
        HBITMAP m_Bitmap;
    #elif UNIX
        WasAuchImmerInUnixAlsBitmapBenutztWird m_Bitmap;
    #else
    #error Nicht implementiert.
    #endif
    

    Oder gibt es eine ganz andere Möglichkeit?



  • ich machs mir in header-dateien, die nur den zweck haben, das vom os wegzuabstrahieren sowas

    #ifdef WIN32
        typedef Bitmap HBITMAP;
    #elif UNIX
        typedef Bitmap WasAuchImmerInUnixAlsBitmapBenutztWird;
    #else
    #error Nicht implementiert.
    #endif
    

    dazu kommen dann noch inlinefunktionen als wrapper für die betriebssystemaufrufe. die brauchte ich ja eh, um exceptions zu werfen, wenn was nicht klappt, statt das immer in den klassen zu testen.

    und in der klasse einfach

    private:
    Bitmap bitmap;
    

    hat mit files und semaphoren und sleep() und so ganz fein funktioniert. ob's für bitmaps angemwessen ist, weiß ich nicht.



  • Aber was machst Du, wenn es jetzt nicht nur um einzelne Membervariablen geht, die bei jeder Variante analog existieren? Was ist, wenn ich in der Windows-Version noch drei Hilfsfunktionen für irgendwas brauche und für die Unixvariante brauch ich noch einmal fünf ganz andere Hilfsfunktionen? Dann ginge kein typedef oder irgendeine Deklaration vor der Klasse, dann müßte ich das #ifdef wieder innen drin haben.
    Aber gibt es denn gar keine Möglichkeit, eine Headerdatei vollkommen sauber zu halten und die betriebssystemspezifischen Dinge komplett in eine andere Datei zu verlagern?



  • ich denke, dann würde ich pimpln.
    (hoffe, ich abe die frage richtig verstanden)

    //Bitmap.hpp
    class BitmapImpl;
    class Bitmap
    {
      private:
        BitmapImpl* pimpl;
      public:
        void resize(int newx,int newy);
    };
    
    //Bitmap.cpp
    #include "Bitmap.hpp"
    #include "BitmapImpl.hpp"
    void Bitmap::resize(int newx,int newy)
    {
       pimpl->resize(newx,newy);
    }
    

    in BitmapImpl.hpp und BitmapImpl.cpp kann ruhig die post abgehen, was bedingte compilierung angeht. vermutlich sogar nur ein bedingten weiterinkludieren nach BitmapImplWindows.hpp und BitmapWindowsLunix.hpp.



  • NES-Spieler schrieb:

    Aber gibt es denn gar keine Möglichkeit, eine Headerdatei vollkommen sauber zu halten und die betriebssystemspezifischen Dinge komplett in eine andere Datei zu verlagern?

    schreib doch eine Wrapper-Klasse um bitmap, sodaß du mithilfe dieser Zwischenschicht plattformunabhängig mit bitmaps hantieren kannst. Dann kannst du alle plattformspezifischen Sachen, wrapper-Klassen, in zentral Dateien nonportable.h/.cpp (oder einam Ordner nonportable/ ) sammeln. Soll der Code später portiert werden, weiß man, daß es reicht, nonportable anzupassen - bei der portierung von größeren Projekten eine große Arbeitserleichterung, weil man nicht mehr alle anderen Quelldateien nach Plattformspezifischem absuchen muß.



  • volkard schrieb:

    ich denke, dann würde ich pimpln.
    (hoffe, ich abe die frage richtig verstanden)

    Ja, Du hast die Frage richtig verstanden. Aber ich weiß nicht so recht. Ich hätte ja gern die Möglichkeit, eine plattformunabhängige Header-Datei zu schreiben, so daß man dann unabhängig voneinander die Implementierungen schreiben kann, die man dann auch benutzen kann, ohne daß ich erst bei jeder Version reingucken muß, ob da noch irgendwelche Implementierungsdetails sind. Und das wäre ja hier auch der Fall, nur daß man eben in einer anderen Klasse nach diesen Details gucken muß.
    Außerdem ist mir aufgefallen, daß das, was Du beabsichtigst, vielleicht auch mit einem Interface realisiert werden kann. Kann das sein? Ich deklariere die Klasse als Interface und lasse dann ableiten. Man muß dann nur festlegen, daß die abgeleitete Klasse auf jedem System denselben Namen hat, denn in dem Fall arbeitet der Benutzer ja nicht mit dem Interface, sondern durchaus mit der abgeleiteten Klasse.

    u_ser-l schrieb:

    schreib doch eine Wrapper-Klasse um bitmap, sodaß du mithilfe dieser Zwischenschicht plattformunabhängig mit bitmaps hantieren kannst.

    Aber der Witz ist ja, daß meine ursprüngliche Klasse Bitmap bereits ein Wrapper sein soll, mit dem man plattformunabhängig mit Bitmaps hantieren kann.



  • NES-Spieler schrieb:

    vielleicht auch mit einem Interface realisiert werden kann. Kann das

    ja, aber das wäre vielleicht zu javanoid.



  • Wie machen das eigentlich die ganzen großen Frameworks, die plattformunabhängig programiert werden, die aber intern natürlich spezifische Funktionalitäten haben und für diese auch ein paar private Funktionen und Variablen deklarieren müssen?


Anmelden zum Antworten