Compiletime Polymorphismus->Problem mit Templates



  • Hallo liebe C++ler,

    ich habe ein Problem was ich selbst nicht ganz in den Griff bekomme und darüberhinaus tue ich mich auch schwer mein Problem zu erklären - ich bitte diesbezüglich um nachsicht.

    Ich instantiiere eine klasse je nach compile-flag und diese ist auch nicht template-basiert. Jetzt habe ich später eine basisklasse die selbst ein templatebasiertes objekt hat (Server). Und dieses Objekt soll nun aber je nach compile-instantiierung unterschiedliche methoden ausführen.

    Mein Problem besteht darin dass ich Methoden in diesem Objekt habe die in der klasse derived1/derived2 vorkommen sollen (weil dazu habe ich die compilezeit-polymorphie gemacht) und abe diese methoden greifen gleichzeitig auf methoden innerhalb dieses objekt zu. Im code habe ich das über das kommentar //b.problemfunc(); markiert. problemfunc() ist nicht implementiert innerhalb der abgeleiteten klassen derived1 und derived2.

    Folgender Pseudocode funktioniert NICHT! Zumindest habe ihc die letzten 3 fehler nicht beheben können aber er veranschaulicht mein Problem - also ein minimalbeispiel.

    Frage: Habe ich eine Möglichkeit mein Ziel zu erreichen in
    void Server<T>::myfunc(base& b)
    in eine methode von entweder derived1 oder derived2 zu springen und dort dann wiederum eine methode von Server aufzurufen ( myfunc2() ) ?

    Habe ich ein falsches Design oder verstehe ich grundlegend etwas nicht?

    Über jegliche Hilfe würde ich mich freuen ! DANKE

    #include <iostream>
    
    class base
    {
    public:
       base() {}
    
      virtual void print() = 0;
       void foo() { std::cout<< "base: " << std::endl;
           print();
       }
    };
    class derived1 : public base
    {
    public:        
      void print()
      {
        std::cout << "derived1" << std::endl;
      }
    };
    class derived2 : public base
    {
      public:        
        void print()
        {
          std::cout << "derived2" << std::endl;
         }
    };
    
    template<class T>
    class Server
    {
            public:
                    void myfunc(base& b);     
                    void myfunc2();
    
    };
    template<class T> void Server<T>::myfunc2()
    {
            std::cout << "test"<< std::endl;       
    }
    template<class T> void Server<T>::myfunc(base& b)
    {
        // Hier will ich jetzt gern auf die methode
            // problemfunc in einer abgeleiteten klase von base
            // zugreifen ABER: In problemfunc muss/wird ein aufruf von 
            // myfunc2 von klasse server gemacht. Wie soll ich das bewerkstelligen?
        //b.problemfunc();
    }
    
    template<class T> 
    class CBase
    {
            public:
    
               CBase<T>();
               void bar(base& b);
                    // noch weitere virtual functions...
               T* Server;
    };
    template<class T> CBase<T>::CBase() 
    {
            Server = new Server<T>();
    }
    
    template<class T> void CBase<T>::bar(base& b) {
        //Hier weiß ich nicht wie weiter
        // Ich will jetzt je nach 
        Server.myfunc(b);
    }
    
    int main()
    {
      base* b = NULL;
    #ifdef MYFLAG
      b  = new derived1();
    #else
      b = new derived2();
    #endif
    
      CBase<double> *cbase = new CBase<double>();
      cbase->bar(b);
    
      delete b;
      delete cbase;
    }
    


  • Also eigentlich sollte dien Wunsch durch die Polymorphie bereits abgegolten sein. Polymorphie bedeutet nicht einfach nur, dass du verschiedene Objekte mit der gleichen Basis als Argument verwenden kannst.

    class basis
    {
       public:
       virtual void func1() = 0;
    };
    class abgel1 : public basis
    {
       public:
       virtual void func1(){};
    };
    class abgel2 : public basis
    {
       public:
       virtual void func1(){};
       void func2(){};
    };
    
    int main()
    {
       basis * p = new abgl1();
       p->func1();  // func1 aus abgel1
       delete p;
    
       p = new abgl2();
       p->func1(); // func1 aus abgel2  
    
       return 0;
    }
    

    Möchtest du jedoch abhängig von der real vorhandenen Klasse eine Funktion aufrufen die es in der anderen nicht gibt(Wie in diesem Beispiel func2 aus abgel2), kannst du vorher mit dynamic_cast prüfen welche Klasse du eigentlich vor dir hast.
    dynamic_cast gibt entweder einen gültigen Zeiger zurück, falls es das entsprechende Objekt ist ansonsten 0, jedoch kann dieser Cast auch Exceptions werfen, die genauen Kriterien weiß ich jetzt nicht.

    if(dynaic_cast<abgel2*>(p))
    {
       p->func1();
       p->func2();
    }
    else
       p->func1();
    

    So als Beispiel.

    Möchtest du in einer aufgerufenen Klasse eine Funktion des Aufrufers verwenden, muss die Aufgerufene Klasse den Aufrufer natürlich können.

    class cl2; // vorwärtsdeklaration
       class cl1
       {
          func(cl2 * c2)
           {
              c2->func();
           }
       }
    
       class cl2
       {
          ...
       }
    

    Alternativ könntest du auch eine Programmstruktur überlegen in der du dieses Flaggedöns nicht brauchst, was ich persönlich vorziehen würde.

    Bin mir nicht ischer ob ich dich richtig verstanden hab, hab aber einfach mal geantwortet.



  • Warum überhaupt Laufzeitpolymorphie, wenn du schon zur Compilezeit (genauer gesagt schon beim Präprozessordurchlauf, deiner Flags nach) die konkrete Instanziierung kennst?

    Du kannst natürlich keine Methoden aufrufen, die nicht einmal deklariert sind. Aber wenn die Klassen, die du als Template-Argumente einsetzt, eine bestimmte Schnittstelle erfüllen, kannst du deren Funktionen aufrufen und vor allem statisch binden.

    class foo
    {
        void problemfunc();
    };
    
    class bar
    {
        void problemfunc();
    };
    
    template <typename T>
    class tpl
    {
        T* ptr;
    
        void func()
        {
            ptr->problemfunc();
        }
    };
    


  • Irgendwie denkt man da an c++


Anmelden zum Antworten