Basisklasse in eine abgeleitete Templateklasse casten



  • Du hast von C++ offensichtlich keine Ahnung. Naja gut, OK, deswegen fragst du ja hier. Ein netterer Ton wäre aber auch ... nett.

    Klare Antwort: nein, was du da machen willst geht so nicht.

    Asserti schrieb:

    Du MUSST den genauen Typ kennen, bzw. solltest wohl die Basis Klasse benutzen.

    Kenn ich aber nicht. Das will ich ja mit RTTI heraus finden.

    Warum möchtest Du die Typen unterscheiden?

    Na weil verschiedene Funktionalitäten ausgeführt werden müssen.

    Geht aber nicht. Ich gehe davon aus dass es sich um einen Design-Fehler deinerseits handelt.

    Aber selbst wenn das Design OK sein sollte, wenn man es unabhängig von den Möglichkeiten die C++ bietet betrachtet (bzw. eben wie in diesem Fall: nicht bietet): es geht eben in C++ nicht, d.h. du musst es irgendwie anders machen.

    Wie können wir dir aber auch nicht sagen, wenn du uns nicht sagst, was dein Beweggrund war, so etwas zu versuchen.



  • Du hast von C++ offensichtlich keine Ahnung

    Na wenn du meinst 🙄

    Klare Antwort: nein, was du da machen willst geht so nicht.

    Also gut. Das ist doch eine Aussage. Dann mach ich es anders.

    Ich gehe davon aus dass es sich um einen Design-Fehler deinerseits handelt.

    Nur weil du es nicht verstehst, oder es nicht geht, muss es noch lang kein Design fehler sein.



  • 🙄


  • Mod

    Ich sehe das auch als Desingfehler.

    Wenn es verschiedene Funktionen gibt, kannst Du zum Beispiel Interfaces erfragen die das Objekt zum Beispiel unterstützt, so wie es COM z.B. macht.

    Jeden Typ in einem switch case und einem dynamic_cast zu prüfen halte ich für falsch.

    Du findest übrigends nette Lösungen für solche Probleme in den "Design Patterns", oder auch in "Effective C++"



  • Hallo Martin

    Wenn es verschiedene Funktionen gibt, kannst Du zum Beispiel Interfaces erfragen die das Objekt zum Beispiel unterstützt.

    Hört sich interessant an. Kannst du mir das ein bischen näher erläutern. Habe ich noch nicht ganz verstanden.

    Du findest übrigends nette Lösungen für solche Probleme in den "Design Patterns", oder auch in "Effective C++"

    Das "Design Patterns" Buch habe ich. Da habe ich aber kein passendes Muster gefunden. Das "Effective C++" kannte ich noch gar nicht. Danke für den Tipp.



  • Bitte 🙂



  • Wenn es ein Designfehler ist das swith case, dann müsst es doch eine verständliche Lösung geben.

    Vieleicht das Design zum besseren Verständnis:
    Es beruht auf dem Composite Muster

    Klasse A -> Basisklasse / abstrakt

    Klasse B -> abgeleitet von A / Templateklasse
    Klasse C -> abgeleitet von A

    Klasse B enthält einen Wert vom typ T
    Klasse C stellt eine Gruppe dar die wiederum Objekte von Klasse A (also B oder C) aufnehmen kann.

    Nun wird in einer Methode X einer weitere Klasse ein Objekt der Klasse A (also B oder C) übergeben.

    So nun soll eine weitere Methode X aufgerufen werden. Diese ist nun abhängig ob es sich um ein Objekt der Klasse B oder um ein Objekt der Klasse C handelt.

    Ich dachte nun das lässt sich mit Hilfe von RTTI lösen. Aber wie bereits festgestellt geht es nicht da es sich bei Klasse C um eine Templateklasse handelt.

    Hoffe ich habe es verständlich ausgedrückt (nicht böse gemeint 🙂 )

    Vieleicht könnt ihr mir nochmals helfen.



  • Asserti schrieb:

    So nun soll eine weitere Methode X aufgerufen werden. Diese ist nun abhängig ob es sich um ein Objekt der Klasse B oder um ein Objekt der Klasse C handelt.

    Es ist natürlich schwer etwas zu sagen, weil man nur einen kleinen Ausschnitt des Ganzen kennt. Das schreit doch nach einer virtuellen Methode - die evtl nochmal eine Referenz auf die aufrufende Klasse (die mit der Methode x) als Parameter hat.



  • Es ist natürlich schwer etwas zu sagen, weil man nur einen kleinen Ausschnitt des Ganzen kennt.

    Jetzt habe ich doch schon extra weiter ausgeholt. 🙂 Alles andere ist überflüssig.

    Das schreit doch nach einer virtuellen Methode

    Was soll die Methode bewirken und wo soll die hin?



  • Asserti schrieb:

    Es ist natürlich schwer etwas zu sagen, weil man nur einen kleinen Ausschnitt des Ganzen kennt.

    Jetzt habe ich doch schon extra weiter ausgeholt. 🙂 Alles andere ist überflüssig.

    Naja du musst es ja wissen.

    Das schreit doch nach einer virtuellen Methode

    Was soll die Methode bewirken und wo soll die hin?

    Na in die Klasse A natürlich.
    Weisst du was virtuelle Funktionen/Methoden sind?
    Vermutlich nicht. Lies es nach, dann wirst du verstehen wie das mit einer virtuellen Funktion ganz einfach und ohne if/switch() geht.



  • Weisst du was virtuelle Funktionen/Methoden sind?
    

    Ja stell dir mal vor. Egal.
    Ich kann die Klasse A aber nicht erweitern. Ich weiß, wieso, weshalb, warum.

    Gibt es eine Lösung mit meiner Einschränkung?



  • Das Problem ist: Ich kann zwar die Basisklasse um eine Virtuelle Funktion erweitern. Aber wie soll ich das bitte die Funktion in den spzeiellen Templateklassen überschreiben. Diese sind nur Typdefs auf die Templateklasse.

    typedef CClassB<bool> CBooleanVar;
    typedef CClassB<int> CIntVar;
    

  • Mod

    Kopfschüttel. Dann mach Klassen draus:

    class CBooleanVar : public CClassB<bool> 
    {
      virtual void MyVirtualImplementation();
    };
    
    class CIntVar: public CClassB<int> 
    {
      virtual void MyVirtualImplementation();
    };
    

    Im template CClassB wird dann die entsprechende pure virtuelle Funktion deklariert.



  • Schön nun wird aber entschieden in der Klasse A B oder C. Meine Entscheidung sollte aber in der Klasse erfolgen in der die Methode X implementiert ist.


  • Mod

    Ich verstehe Dich nicht?

    Du hast nun die Möglichkkeit je Typ eine unterschiedliche Behandlung zu ermöglichen, oder zu fragen was für ein Typ es sit (geht auch über eine virtuelle Funktion).

    Du kannst also jetzt jederzeit die Infos nutzen, auch in Deiner Funktion X.
    Obwohl genau dies mieser Stil ist... Jede Typenerweiterung muß auch genau in dieser Funktion nachgezogen werden... Vergisst Du es muss es zu einer Fehlfunktion kommmen.



  • oder zu fragen was für ein Typ es ist (geht auch über eine virtuelle Funktion)

    Meine Fallunterscheidung betrifft eigentlich nur die Klasse B und C. Es gibt keinen Unterschied in den speziellen Klassen. Nun wäre eigentlich der einfache Fall ein if elseif construct. Sprich ich sollte nur wissen ob es sich bei der übergebenen um Klasse B oder C handelt. Das ist ja kein Problem.

    Dann will ich Methode X aufrufen die ein Objekt der Klasse B aufnimmt und eine Methode X die ein Objekt der Klasse C aufnimmt. Dazu müss ich das Objekt je nach Unterscheidung Casten in C oder B. In C ist kein Problem. Aber wie schaffe ich es in Klasse B zu casten. Hier liegt ja das Problem. Nicht beim herausbekommen um welche Klasse es sich handelt.



  • Und warum willst du nicht folgendes:

    class A
    {
      public:
        virtual void DoSomething()=0;
    };
    
    class B
    {
      public:
        virtual void DoSomething()
        {
           // ...
        }
    };
    
    template <typename T>
    class C
    {
      public:
        virtual void DoSomething()
        {
           // ...
        }
    };
    

    Da brauchst du keine Fallunterscheidung.

    Generell ist es einfach nicht gut den Code für eine solche Unterscheidung in irgendeine Methode reinzumachen. Vererbung löst das meist besser.

    Ohne mehr zu wissen was die Klassen machen und was die Klasse mit der Methode X macht lässt sich schwer mehr sagen. Du wirst dann leider immer solche ungenauen Antworten bekommen - die dich wohl nicht weiterbringen.

    Du wirst wohl oder über kaum drum herum kommen in der Template Klasse eine Unterscheidung einzuführen um welchen Typ es sich handelt. Diese Unterscheidung kannst du natürlich auch z.B. in eine externe Klassen auslagern.

    template <typename T,class Helper>
    class C
    {
      public:
        virtual void DoSomething()
        {
           helper.DoSomething();
        }
      private:
        Helper helper;
    };
    typedef C<int,IntHelper> CInt;
    typedef C<int,DoubleHelper> CDouble;
    

    Somit kannst du dir auch ein "ich-muss-alles-wissen" if sparen.

    Aber ich denke es ist schwer mehr zu sagen/helfen ohne die Klassen (bzw deren Aufgabe) genau zu kennen.



  • Also.

    Die Klasse B ist eine Klasse die einen elementaren Datentyp enthält. Klasse C ist eine Klasse die ein Container darstellt der Objekte von Klasse B aber auch wiederum Objekte von Klasse C aufnimmt. Deshalb beinhaltet der Container Objekte vom Typ der Klasse A.

    So nun würde ich gerne eine Methode aufrufen. Dieser übergebe ich ein Objekt also entweder von der Klasse B oder C. Demzufolge A.

    Nun würde ich gerne in dieser Methode X den Wert vom Objekt B mit einer gespeicherten Variable vergleichen. Nun könnte ich einfach den Wert von B abfragen. Dazu müsste ich in B casten. Geht aber nicht. Eine virtuelle Funktion geht nicht da Klasse C keinen Wert hat nur einen Container mit mehreren Werten. Für den Klasse C fall müsste ich eine Schleife durchlaufen.

    Verständlich?



  • Wenn die Methode x ein Objekt A bekommt, aber gerne Objekte B verarbeiten möchte ist was falsch. Es hört sich alles danach an, als ob Methode X viele Sachen macht die speziell für eine Klasse sind.

    Entweder du sagst
    1)
    Objekte vom Typ A können mit Werten verglichen werden (-> virtuelle Methode)
    2)
    Nur Objekte vom Typ B können mit Werten verglichen werden (z.B. für Typ C machts keinen Sinn).
    Es macht hier wenig Sinn einer einer Methode 'Tier' zu übergeben, wenn sie eine 'Maus' will.

    Ich sehe den Sinn noch nicht warum du A übergeben musst.

    Du hast natürlich die Möglichkeit eine solche Methode zu machen und z.B. für Klassen bei denen ein Vergleich keinen Sinn macht einen Sinnvollen default Wert zurückzugeben.



  • Ich sehe den Sinn noch nicht warum du A übergeben musst.

    Es macht Sinn. Klasse B sagen wir mal ist eine Variable. Klasse C ist eine Gruppe von Variablen aber nicht nur von B sondern kann auch wieder von sich selber.

    Das ist ja das Compositemuster.

    So jetzt übergebe ich der Funktion die Basisklasse.

    Bei Klasse B wird ein Wert mit einem alten verglichen. Wenn ungleich dann liefert diese true zurück.

    Bei Klasse C werden alle Werte mit einer alten Liste von werten verglichen. Sobald sich ein Wert geändert hat liefert die Methode true zurück.


Anmelden zum Antworten