abstrakte Funktion in innerer Klasse aufrufen



  • Hio!

    Ich habe ein relativ komplexes Problem, was ich bisher unzureichend gelöst habe: Ich habe eine Klasse (wahrscheinlich ein Template), die einige abstrakte Funktionen enthält, damit der Nutzer diese überschreiben muss. Dazukommt, dass ich als Hilfsklasse die innere Klasse brauche, die zum großteil Daten hält und diese auf einer grundlegenden Ebene manipuliert. Diese innere Klasse / "Hilfsklasse", soll nicht nach außen bekannt sein und am liebsten nur dann instanziierbar sein, wenn auch die äußere Klasse existiert.
    Momentan überlege ich mir das in etwa so:

    template <typename T> class Outer<T> {
      private:
        class Inner {
          public:
            int a;
            int function();
         };
      public:
        virtual int someOtherFunction();
    };
    

    Nun möchte ich in "function()" die vom User überschriebene Funktion "someOtherFunction()" aufrufen und evt. Änderungen an "a" durchführen.
    Soweit ich das Konzept der inneren Klassen verstanden habe,wird das nach diesem Aufbau nicht so wirklich was: "Inner" ist zwar an den Geltungsbereich von "Outer" gebunden, aber durchaus noch eine eigenständige Klasse, d.h. ich könnte mit Outer::Inner x; sogar Objekte vom Typ "Inner" direkt erstellen, oder?

    Gibt es nun eine Möglichkeit, dass der Nutzer ein Objekt vom Typ "Inner" niemals erstellen kann (Man soll gar nicht wissen, dass dort eine weitere Klasse vorhanden ist) und dieses immer implizit über ein Objekt(!) von "Outer" läuft, sodass ich innerhalb von "Inner" auch abstrakte Funktionen von "Outer" aufrufen kann?

    Gruß

    Bubbles



  • Dadurch, dass Outer<T>::Inner eine innere Klassenvorlage ist, ergeben sich Unterschiede allein für die Namensauflösung, ansonsten werden daraus ganz normale Klassen gestanzt. Wenn deren Objekte ein Outer-Objekt als Besitzer kennen sollen, musst du es ihnen bekannt machen, beispielsweise

    #include <iostream>
    
    template<typename T>
    class Outer {
    public:
      Outer() : ownee_(*this) { }
    
      void do_something() const { ownee_.call_me_back(); }
      void callback() const { std::cout << "Hallo, Welt." << std::endl; }
    
    private:
      class Inner {
      public:
        Inner(Outer &owner) : owner_(owner) { }
    
        void call_me_back() const {
          owner_.callback();
        }
    
      private:
        Outer &owner_;
      };
    
      Inner ownee_;
    };
    
    int main() {
      Outer<int> o;
    
      o.do_something();
    }
    

    Dabei kann Outer::callback() problemlos auch pure virtual sein.

    Die Anforderung, dass ein Benutzer Objekte der Klasse Inner nicht direkt erstellen kann, ist dadurch gegeben, dass Inner in Outer private ist. Ansonsten kann man solche privaten Klassen aber auch in einem als für Implementationsdetails gekennzeicheten Namensraum versenken ("detail" und "impl" sind beliebte Namen) und sich auf den Standpunkt stellen, dass jemand, der sich auf undokumentierte Implementationsdetails stützt, selbst schuld ist, wenn sein Code nach einem Bibliotheksupdate nicht mehr kompiliert.



  • Hio!

    Danke für den Tipp. Kommt mir zwar etwas "gehackt" vor, aber funkt 😉

    Gruß

    Bubbles


Anmelden zum Antworten