Statische Polymorphie für 'Liste' von Objekt-Typen



  • Hallo zusammen,

    ich habe folgendes Problem. Mein Netzwerk besteht aus verschiedenen (zur Kompilierzeit bekannten) Typen von Knoten und Kanten, wobei bestimmte Knoten nur mit bestimmten Kannten verbunden werden können. Ich verdeutliche es mal durch Formen und Farben, wobei es in Wirklichkeit nicht nur Eigenschaften sind, sondern komplett andere Funktionsweisen.

    Als Beispiel:

    * ein quadratischer Knoten kann nur mit roten Kanten verbunden werden.
    * ein dreieckiger Knoten kann nur mit weißen Kanten verbunden werden.
    * ein runder Knoten kann mit beiden Typen verbunden werden.

    Jetzt möchte ich das Netzwerk verändern. Dazu übergebe ich pro Knoten-Typen eine 'Strategie' nach der er versuchen soll neue Kanten zu finden.

    Jetzt kann ich natürlich eine Liste für Knoten und eine für Kanten machen und jede Menge dynamic_casts zur Typ-Überprüfung.
    Als Alternative kann ich aber auch ein Tupel mit Listen pro Typ machen und zur Kompilerzeit dann 'Erkennen', welche Typen miteinander interagieren können.

    Also generell find ich die Idee mit dem Tupel gut, allerdings hab ich (glaub ich) noch nie gesehen, dass jemand nen Tupel nimmt um die genauen Typ-Infos zu behalten. Diese Tatsache macht mich skeptisch und ich frag mich, welche Gefahren bei dem Ansatz drohen können.

    Würdet ihr mir von Tupeln mit verschiedenen Objekttypen aus irgendeinem Grund evtl. abraten?

    Gruß,
    XSpille



  • Wie sind deine Knoten/Kanten gespeichert? Hast du volle Typinformation oder benutzt du abstrakte Basisklassen? Im letzteren Fall reicht statische Polymorphie alleine nämlich nicht.

    Also kannst du vielleicht kurz deine Knoten- und Kantenklassen hinschreiben (wichtig sind vor allem deren Beziehungen untereinander sowie die verwendete Abstraktion)?



  • Nexus schrieb:

    Wie sind deine Knoten/Kanten gespeichert? Hast du volle Typinformation oder benutzt du abstrakte Basisklassen? Im letzteren Fall reicht statische Polymorphie alleine nämlich nicht.

    Also kannst du vielleicht kurz deine Knoten- und Kantenklassen hinschreiben (wichtig sind vor allem deren Beziehungen untereinander sowie die verwendete Abstraktion)?

    Warum reicht bei abstrakten Basisklassen eine statische Polymorphie nicht aus?

    In Wirklichkeit handelt es sich um ein Flussnetz (Neuronales Netz)
    Also nicht klassisch und deswegen fließen mehr als nur Kommazahlen.
    (Ob es sinnvoll ist, sei mal dahingestellt)

    Also die Kanten transformieren Daten und haben die Form:

    struct IEdge{
    virtual void forward() = 0;
    };
    
    template<typename TSource, typename TTarget, typename TParam, void TFunc(const TSource&, TTarget&, const TParam&)>
    struct Edge : public InputInfo<TSource>, public OutputInfo<TTarget>;
    

    Wie du siehst, ist es (bisher?) in Wiklichkeit nur eine Kantenklasse, jedoch mit verschiedenen Template-Parametern.

    Also meine Knoten sind wirklich unterschiedliche Klassen die alle eine Ausgabe erzeugen. Teilweise mit internen Zuständen, teilweise ohne.

    struct INode{
    virtual void calculate_output() = 0;
    };
    

    Als Beispiel:

    struct SimpleNode : public INode{
    void connect_input_edge(int i, OutputInfo<float>& output));
    void connect_input_flag(OutputInfo<bool>& output));
    void connect_output1(InputInfo<bool>& input));
    void connect_output2(InputInfo<float>& input));
    };
    

    Ich weiß nicht, ob dir das weiterhilft, da ich nicht weiß, worauf du hinaus möchtest...
    Aber ich wollte halt nicht zu viel Code posten...

    Evtl. dass man (z. B.) von aussen nicht (einfach) über alle INode bzw. IEdge iterieren kann?

    Gruß,
    XSpille



  • XSpille schrieb:

    Warum reicht bei abstrakten Basisklassen eine statische Polymorphie nicht aus?

    Weil du den dynamischen Typen erst zur Laufzeit kennst, folglich muss dynamische Polymorphie her.

    Ich nehme mal an, du speicherst irgendwo Container mit IEdge* und INode* als Elementen (oder anderer Zeigertyp). Wenn schon im Voraus bekannt ist, wie viele Knoten- und Kantentypen es geben wird, könntest du sowas machen (nur als Inspiration):

    struct IEdge
    {
        virtual unsigned int GetFlag() const = 0;
    };
    
    struct RedEdge : IEdge
    {
        static const unsigned int Flag = 1 << 0;
        virtual unsigned int GetFlag() const { return Flag; }
    };
    
    struct WhiteEdge : IEdge
    {
        static const unsigned int Flag = 1 << 1;
        virtual unsigned int GetFlag() const { return Flag; }
    };
    
    struct INode
    {
        virtual bool IsCompatible(const IEdge& edge) const = 0;
    };
    
    struct RoundNode : INode
    {
        virtual bool IsCompatible(const IEdge& edge) const
        {
            return edge.GetFlag() & (RedNode::Flag | WhiteNode::Flag);
        }
    };
    


  • Jetzt hab ich verstanden, was du meinst...

    DANKE dir! 👍

    Deinen Alternativ-Vorschlag finde ich persönlich stilistisch nicht schön...



  • XSpille schrieb:

    Deinen Alternativ-Vorschlag finde ich persönlich stilistisch nicht schön...

    Nicht so schön wie dynamic_cast oder wie?

    Soll im Übrigen wie gesagt nur eine Inspiration sein. Du kannst versuchen, Abhängigkeiten der einzelnen Klassen zu verringern und IDs/Flags automatisch zu vergeben.


Log in to reply