Designfrage pImpl



  • Guten Abend,

    gleich zur Sache:

    // A.hpp
    
    class A{
        class impl;
        impl* pImpl;
    public:
        A();
    };
    
    // A.cpp
    
    class A::impl{
         C *ptr;                 // C ist irgendein implementierungsabhängiges Konstrukt
         impl(C* p) : ptr(p){}
    };
    
    A::A() : pImpl(new impl){}
    

    Meine Frage hierzu:
    Wie bring ich dem Interface A "schonend" bei, dass A::impl bezüglich der Konstruktion einen Pointer auf C verlangt? Entsprechend der Implementierung A einen anderer Konstruktor zu spendieren find ich persönlich nicht sehr schön. Ich denke, dass wird auch generell so gesehen?! 😉

    Andererseits dachte ich mir, ich könnte natürlich noch einen weiteren Typen einführen, der einfach nur das C* kapselt:

    class Capsule{
       C* ptr;
       Capsule(C* p) : ptr(p){}  
    
       C* get_impl(){
         return ptr;
       }
    };
    

    und A per Konstruktor eine Instanz von Capsule übergeben, die dann entsprechend an den Konstruktor von A::impl weitergeben wird, wo letztlich die get_impl-Methode aufgerufen wird, um an den Pointer zu kommen. Ist diese Variante so in Ordnung bzw. wie löst ihr solche Konstrukte auf?



  • Also entweder Klasse A braucht dieses Konstrukt insgesamt (also öffentlich), oder der Konstruktor von A muss das A::impl auch nicht übergeben. Wo soll dieses C denn herkommen?



  • Decimad schrieb:

    Also entweder Klasse A braucht dieses Konstrukt insgesamt (also öffentlich), oder der Konstruktor von A muss das A::impl auch nicht übergeben. Wo soll dieses C denn herkommen?

    Ok, ist nicht ganz deutlich geworden. Stell dir also vor, dieser Pointer auf C stammt aus irgendeiner implementierungsspezifischen Factory-Funktion:

    C* factoryC();
    
    C* ptr = factoryC(); 
    A a(ptr);            // Sollte A wirklich implementierungsspezifische Werte erwarten?
    


  • Naja.

    Wenn alle (bzw. zumindest einige) mögliche Implementierungen von A etwas brauchen, damit man ein A erstellen kann, dann ist zumindest dieser Umstand schonmal nicht implementierungsspezifisch.

    Wenn der genaue Typ implementierungsspezifisch ist, dann reich doch einfach einen Basisklassenzeiger rum.

    CBase* AParameterFactory();
    
    class A
    {
    public:
        A(CBase* parameter);
    };
    

    Die konkrete Klasse C (die von CBase abgeleitet ist) muss für den User-Programmierer nichtmal sichtbar sein (z.B. weil sie in einem privaten Headerfile definiert wird, oder gleich in einem anonymen Namespace).

    Das ist eine Möglichkeit.

    Eine andere Möglichkeit wäre gleich die Factory bzw. ein Factory-Object an A zu übergeben, so dass A sich das benötigte Objekt selbst erstellt.

    ----

    Wenn das auf dein spezielles Problem schlecht passt, beschreib dein Problem etwas konkreter.


Anmelden zum Antworten