Verkettete Liste: verschiedene Objekte ablegen und deren Funktionen aufrufen



  • Hallo Big Brother,

    ich hab grad noch was gesehn was mit nicht gefällt bei der Lösung:

    Die "Member"-Funktionen haben void-Pointer als Parameter.



  • stefan-tiger schrieb:

    Hallo Big Brother,

    deinen ersten Satz verstehe ich nicht. Ist das ein Problem für Dich?

    Nein, kein Problem. Du hast ne new-Funktion, hast sich also erledigt.

    stefan-tiger schrieb:

    Hierbei sind aber die Einschränkungen gegeben, dass

    (a) alle Klassen diesen Funktionspointer haben müssen

    Oder eine Art Objekt ID, die ebenfalls alle Strukturen haben müssen, wobei der Zugriff auf die Funktionen umständlicher ist und länger dauert.

    stefan-tiger schrieb:

    (b) der Funktiinspointer im struct aller Klassen immer an der selben Stelle steht

    Ja, die Reihenfolge der Strukturelemente ist eingeschränkt. Inwiefern ist das für Dich problematisch?

    stefan-tiger schrieb:

    (c) der Funktionspointer immer die selbe Signatur in allen Klassen haben muss

    Dank der Zeigerübergabe aber flexibel ist.

    stefan-tiger schrieb:

    Der Vorteil dieser Lösung ist allerdings, dass es dem Basis-Klassen-Konzept von C++ näher kommt und dass die Implementierung zwischen der Liste und den Objekten besser getrennt ist.

    Je näher an C++ ,desto besser?
    Da drängt sich mir die Frage auf: Warum schreibst Du das nicht gleich in C++ ?

    stefan-tiger schrieb:

    Die "Member"-Funktionen haben void-Pointer als Parameter.

    Was gefällt Dir daran nicht? Du kannst auch nen unsigned long nehmen oder sowas.

    Gruß,
    B.B.



  • Big Brother schrieb:

    ...

    stefan-tiger schrieb:

    (b) der Funktiinspointer im struct aller Klassen immer an der selben Stelle steht

    Ja, die Reihenfolge der Strukturelemente ist eingeschränkt. Inwiefern ist das für Dich problematisch?
    ...

    stefan-tiger schrieb:

    Der Vorteil dieser Lösung ist allerdings, dass es dem Basis-Klassen-Konzept von C++ näher kommt und dass die Implementierung zwischen der Liste und den Objekten besser getrennt ist.

    Je näher an C++ ,desto besser?
    Da drängt sich mir die Frage auf: Warum schreibst Du das nicht gleich in C++ ?

    stefan-tiger schrieb:

    Die "Member"-Funktionen haben void-Pointer als Parameter.

    Was gefällt Dir daran nicht? Du kannst auch nen unsigned long nehmen oder sowas.

    Gruß,
    B.B.

    Problematisch ist es nicht direkt. Ich versuche nur eine so weit wie möglich allgemeingültige Lösung zu finden. Die Strukturen haben dann eben gewissen "organisatorischen" Regelen entsprechen und sind nichtmehr völlig unabhängig (wären sie mit der Typ-Kennung auch nicht 100%).

    Warum ich nicht C++ verwende? Nun, ich denke ich kann mehr über die "internen" Dinge eines Programms lernen wenn ich in C Dinge selbst machen muss die in C++ inklusive sind bzw. durch Templates und umfangreiche Libraies gekapselt sind.
    Natürlich kann man sich auch deren Implementierungen ansehen...

    An den void-Parametern gefällt mir nicht, dass hier der Code an einer Stelle verändert wurde, weil an einer anderen Stelle eine bestimmte Implementierung gewählt wurde. Anders ausgedrückt: Ohne die verkettete Liste würde man den Member-Funktionen der Klassen einen Pointer des "richtigen" Klassen-Typs übergeben, statt einen void-Pointer.
    Das ist eine Design-Regel die man z.B. anderen Programmierern die Klassen zuliefern möchten mitgeben muss. Das macht es jedenfall nicht einfacher.



  • stefan-tiger schrieb:

    An den void-Parametern gefällt mir nicht, dass hier der Code an einer Stelle verändert wurde, weil an einer anderen Stelle eine bestimmte Implementierung gewählt wurde. Anders ausgedrückt: Ohne die verkettete Liste würde man den Member-Funktionen der Klassen einen Pointer des "richtigen" Klassen-Typs übergeben, statt einen void-Pointer.
    Das ist eine Design-Regel die man z.B. anderen Programmierern die Klassen zuliefern möchten mitgeben muss. Das macht es jedenfall nicht einfacher.

    Ok, ist hier auch machbar und es gefällt mir auch besser als die void*
    Alternative:

    void func_objectA ( ObjectA* object )
    {
        printf ( "%d\n", object->value );
    }
    
    void func_objectB ( ObjectB* object )
    {
    	printf ( "%s\n", object->buf );
    }
    


  • stefan-tiger schrieb:

    In deinem Code ist Klasse=Instanz und es gibt sie nur einmal. Und dieses eine mal ist auch noch zur Compile-Zeit und nicht zur Laufzeit angelegt.
    Daher ist es in deinem Beispiel auch kein Problem die Adresse der "Klasse" abzufragen.

    ich betrachtete objectA und objectB als klasse und Entry_t wäre dann eine instanz der klasse.

    denn eine Klasse in C++

    der ganze vergleich mit c++ hinkt ein bischen, da es sich eben nicht vergleichen lässt. oop in c und oop in c++ sind eben unterschiedliche sachen. ich weiß jetzt nicht genau was c++ aus den klassen macht. aber du solltest bedenken das c++ auch nicht zaubern kann und evtl. die structuren ohne dein wissen anlegt denn irgendwoher muß auch c++ wissen welche function es aufrufen soll. allerdings kann auch der compiler gewisse optimierungen treffen und somit auf den umweg über eine klasse verzichten und die function direkt aufrufen.

    lg lolo



  • Big Brother schrieb:

    void func_objectA ( ObjectA* object )
    {
        printf ( "%d\n", object->value );
    }
    
    void func_objectB ( ObjectB* object )
    {
    	printf ( "%s\n", object->buf );
    }
    

    Hey, das gefällt mir! Sieht meiner Eventqueue sehr ähnlich, deren Draft basiert allerdings auf void*, damals hatte ich aber noch dooferweise eine Trennung von Datenlisten und Funktionslisten und mußte mir irgendeinen Blödsinn ausdenken, Datentypen zu parsen, bis mir irgendwann aufgefallen ist, daß es das gar nicht braucht.

    stefan-tiger schrieb:

    Korrigier mich wenn ich was falsches schreibe:
    In deinem Code ist Klasse=Instanz und es gibt sie nur einmal. Und dieses eine mal ist auch noch zur Compile-Zeit und nicht zur Laufzeit angelegt.
    Daher ist es in deinem Beispiel auch kein Problem die Adresse der "Klasse" abzufragen.

    Deswegen vermeide ich bei C die Begriffe wie Klasse, Objekt und Instanz. Um Methoden und Daten zusammenzuschnallen brauchst Du entweder structs oder Klassen, trotzdem sind sie nicht dasselbe. Zur Compiletime ist eine struct auch nur ein abstraktes Gebilde, eine Definition, ob da ein Funktionspointer drin ist oder nicht. Und es ist völlig egal, ob Du die struct als Frame-element oder als Bestandteil einer Liste auf dem Heap anlegst, das Speicheranlegen erfolgt zur Runtime. Dann ist es aber immer noch nur ein Stück Speicher, das Du sinnvoll füllen solltest und der Funktionspointer typisiert das Ding eben auch erst zur Laufzeit. Erst damit ist das Ding "instantiiert".
    Ergo Klasse != Instanz

    stefan-tiger schrieb:

    Ich möchte aber mehrere Instanzen zur Laufzeit anlegen.

    🤡 Kannst Du ja, bis der Speicher voll ist. Jedes Listenelement ist eine Instanz.

    stefan-tiger schrieb:

    Wichtig ist mir hierbei das "typedef", denn eine Klasse in C++ belegt an sich noch kein Speicher und kann nicht als "lebendes Objekt" vendendet werden, das wird erst mit einer Instanz möglich (oder nicht?).

    Na und, reitest Du deshalb auf dem typedef rum? Du kannst tausend structs deklarieren, sie nehmen zur Runtime kein einziges Byte weg. Der typedef ist nur eine Annehmlichkeit für Schreibfaule.

    Daß der "Schlüssel" (nach BigBrother-Definition) passen muß, kann man positiv oder negativ sehen, ich bin bisher bei void * geblieben, ohne mich weiter zu verkopfen, weil ich in "Zeiger auf irgendwas" die Unverbindlichkeit habe, die mir so vorschwebte. Aber schön, sowas wieder aufgerollt zu sehen, ich werd' mich mal in einer ruhigen Minute nach Jahren unreflektierten Einsatzes über meinen Kram wieder hermachen und gucken, ob das was bringt.
    Danke, B.B. für die Denkanstöße! 😃


Anmelden zum Antworten