Methoden in main verwenden



  • Guten Tag liebe Community!

    Ich programmiere noch nicht sehr lange C++ und bin daher auch noch etwas unsicher.

    Ich habe die Klasse DLL (Double Linked List) erstellt und schon 2 Methoden für diese geschrieben. Leider kann ich diese nicht testen da der Aufruf der Methoden in der Main funktion nicht funktioniert.

    Ich rufe so auf:

    KlassenName.MethodenName(parameter);

    Leider bekomme ich folgende Fehlermeldung:

    error: expected unqualified-id before '.' token

    Woran liegt das? Habt ihr verbesserungsvorschläge?

    Danke im Vorhinein!
    LG Jonny

    Hier noch mein Code

    .h - Datei:

    class DLL{
        struct Knoten{
            int data;
            Knoten *prev;
            Knoten *next;
        };
        Knoten *head = NULL;
        Knoten *end = NULL;
    public:
        DLL();
        void sort_insert(int n);
        void print();
    };
    

    die Datei mit allen Methoden:

    DLL::DLL(){ //Konstruktor
    
    }
    
    void DLL::sort_insert(int n){
        Knoten *node = new Knoten;
        Knoten *node2 = new Knoten;
        node2 = head;
        node->data = n;
        if (head == NULL){
            head = node;
            end = node;
            head->next = end;
            end->prev = head;
        }
        else {
            while (n > node2->data){
                node2 = node2->next;
            }
            node2->prev->next = node;
            node->prev = node2->prev;
            node->next = node2;
            node2->prev = node;
        }
    }
    
    void DLL::print(){
        Knoten* current = head;
        while (current){
            cout << current->data << endl;
            current = current->next;
        }
    }
    

    und die Main

    int main() {   
    
        DLL.sort_insert(1);
        DLL.sort_insert(2);
        DLL.sort_insert(3);
        DLL.print();
        return 0;
    }
    

    Danke Nochmal für eure Hilfe!



  • Warum könnt ihr nur Teile des Quelltextes kopieren 😕

    Hast du bei einer Datei nicht so etwas Ähnliches:

    #ifdef JKDLL_EXPORTS
    #define JKDLL_API __declspec(dllexport) 
    #else
    #define JKDLL_API __declspec(dllimport) 
    #endif
    

    😕

    JK soll die Abkürzung für deinen Nick ...

    Und die Header auch bei dem anderen Quelltext?



  • Die Abkürzung DLL für Double Linked List ist unglücklich gewählt, führt sie doch nur zu Verwirrungen (siehe erste Antwort -> dynamic link library).
    Du brauchst eine Instanz deiner Klasse:

    int main() {   
        DLL dll;
        dll.sort_insert(1);
        ....
    }
    

    Zur Speicherverwaltung wäre auch noch einiges zu schreiben, das spare ich mir jetzt aber mal. Probiers erst einmal so, aber behalte eben im Hinterkopf, dass möglichst ohne besitzende Zeiger gearbeitet werden sollte.



  • In keiner bestimmten Reihenfolge:

    • Wähle einen anerkannten Stil. (Ich rate vom GNU Coding Style ab, außer für GNU-Projekte.)
    • In The C++ Programming Language, 4th Edition, schreibt Bjarne Stroustrup, dass DLL::print etc. Funktionen sind. Methoden sind ein Synonym für virtuelle Funktionen (markiert mit dem Schlüsselwort virtual). Um zu zitieren (§20.3.2):

    A virtual member function is sometimes called a method.

    In C++ muss man Funktionen explizit virtuell machen, in Java ist jede Funktion virtuell und darum eine Funktion.
    Das ist eine Konvention, die ich persönlich befolge. Sie kommt von Herrn Stroustrup selbst, weshalb ich sie für erwähnenswert halte. Du musst sie nicht befolgen, aber von ihr zu wissen könnte nützlich sein.

    • NULL ist C. Seit C++11 gibt es nullptr. Bei meiner GCC-Implementation, Version 7.3.1, ist NULL nur als 0 definiert, ein int-Literal, das implizit zu einem Zeiger konvertiert werden kann, aber typunsicher ist, da es nunmal eigentlich vom Typ int ist. Quatsch wie
    int ichBinEinInt = NULL;
    

    kompiliert möglicherweise ohne Probleme. Typdeduktion mit auto kann so auch schiefgehen.
    Verwende nullptr für bessere Typsicherheit.

    • Schreibe Code in einer Sprache und gerne auf Englisch. Englisch ist die Lingua franca der Informatik. Das ist aber natürlich sehr kontextabhängig, also merke dir nur, dass Englisch sehr stark mit der Programmierung verbunden ist und entscheide nach eigenem Ermessen.
    • Dein Konstruktor macht nichts und ist äquivalent zum Standard-Konstruktor. Wenn du nur einen nichtstuenden Konstruktor ohne Argumente willst, kannst du Deklaration und Definition des Konstruktors einfach entfernen, der Compiler generiert ihn automatisch. Seit C++11 gibt es auch die = default-Syntax, sodass
    DLL() = default;
    

    explizit aussagt, dass du einen Standard-Konstruktor haben willst. Was du verwendest -- deine Sache. Wähle und bleibe konsistent in deiner Wahl.

    • Jegliche Antworten bezüglich Syntax und Semantik der Programmiersprache C++ findest du im C++-Standard. Schwer zu lesen (nicht nur für Anfänger), aber etwas, wovon jeder, der etwas mit C++ am Hut hat, wenigstens Kenntnis nehmen sollte. Einen Entwurf für den C++17-Standard findest du hier als PDF. Die offiziellen Standards kosten etwas, die Entwürfe sind nah am Standard und kostenlos. Schau gerne mal rein und schwelge in Ehrfurcht vor der enthaltenen Komplexität und dem Umfang der Programmiersprache selbst. (Sagte ich, Englisch ist wichtig? Ist auf Englisch.)
    • Ich stimme yahendrik zu, dass DLL mit Dynamic Link Library zu verwechseln ist. Nenne die Klasse einfach DoublyLinkedList! Code soll lesbar sein und Abkürzungen können genutzt werden, wenn sie allgemeingültig sind und außerdem nicht irreführend wie "DLL". i, j, k für Indizes, buf für Pufferspeicher, tmp für temporäre Variablen... dass sind valide Abkürzungen. Wenn du dich dreckig fühlst, kannst du einen Alias einführen:
    using DLL = DoublyLinkedList;
    

    Absolut nicht zu empfehlen, aber erfüllt seinen Zweck.

    • Wisse, dass du nur eine Liste von ints erzeugen kannst. Für generische Klassen, insbesondere Container-Klassen (siehe std::list und STL), nutze Templates. Nichts, was ein Anfänger wissen muss, nur ein Hinweis auf die Möglichkeiten in C++. Und fange ja nicht mit void-Zeigern an, das gehört nicht in C++-Code, weil typunsicher und unhandlich as f***!
    • std::endl ist vielleicht nicht, was du denkst.
    cout << current->data << endl;
    

    Leert nämlich den std::cout-Pufferspeicher. Alles, was du zu std::cout schreibst, wird erstmal in einem Pufferspeicher gespeichert. Sobald du diesen Speicher "flush"st (dt. spülst), wird erst etwas auf dem Bildschirm erscheinen. std::endl macht das jedes einzelne Mal! Das heißt, es wird jedes Mal, völlig unnötig, der Puffer geleert, was sehr ineffizient ist und das Prinzip des Pufferspeichers komplett die Toilette hinunterflusht. Nutze ganz einfach das Newline-Zeichen '\n' für eine neue Zeile! Unser Landsmann Dietmar Kühl hat auf der CppCon 2017 einen kleinen Vortrag dazu gehalten.

    • Du hast ein Speicherleck:
    Knoten *node = new Knoten;
    Knoten *node2 = new Knoten;
    

    erzeugt zwei Knoten auf dem "free store" (auch Heap genannt), welche anschließend mit delete wieder "befreit" werden müssen, um dem Speichermanager zu sagen, dass der Platz wieder frei ist. Normalerweise sollte das Betriebssystem den Speicher, der nicht wieder befreit wurde, automatisch bei Beendigung des Programms befreien, allerdings garantiert das der C++-Standard nicht und für länger laufende Programme ist dieser Speicher für die komplette Laufzeit belegt, obwohl er vllt. nach gewisser Zeit gar nicht mehr benötigt wird.
    C++03 hat std::auto_ptr. Seit C++11 gibt es std::unique_ptr und std::shared_ptr. Nutze diese Zeiger-Wrapper, um auf dem Heap alloziierten Speicher automatisch zu befreien oder nutze RAII (Resource Acquisition Is Initialization, dt. Ressourcenbelegung ist Initialisierung) manuell, um solch ein Dilemma zu vermeiden. C++ hat keinen Garbage Collector wie Java!

    • Eng verbunden mit dem vorherigen Punkt: Die Zeile
    node2 = head;
    

    weist node2 einen neuen Wert zu, sodass der Zeiger zum Heap-Speicher, den du gerade mit new angefordert hast, verloren geht und zwingend zu einem "memory leak" (dt. Speicherleck) führt. Es gibt genügend Ressourcen wie das Internet oder Bücher, um C++ ordentlich zu lernen. Nutze diese Möglichkeiten, um solche Fehler einfach auszumerzen.

    • Wenn du Fehlermeldungen postest, immer die volle Meldung mit Zeilenangabe.
    • Der Code
    DLL.sort_insert(1);
    DLL.sort_insert(2);
    DLL.sort_insert(3);
    DLL.print();
    

    kompiliert nicht, weil DLL kein Objekt, sondern eine Klasse ist. Lerne die Grundlagen der objektorientierten Programmierung, wenn nicht bereits vorhanden. Erzeuge ein Objekt der Klasse DLL wie folgt:

    DLL dll;
    

    Nun kannst du die Funktionen auf dem Objekt dll aufrufen.

    • Die Zeile
    return 0;
    

    ist redundant. Wenn du kein return-Statement in der main-Funktion benutzt, wird automatisch 0 zurückgegeben. Die Header-Datei <stdlib.h> (<cstdlib>, wenn du Funktionen und Variablen in den std-Namespace packen willst) definiert EXIT_SUCCESS und EXIT_FAILURE. Ich persönlich benutze, wenn überhaupt, immer diese Makros, nicht irgendwelche Literale.

    Dein Code ist letztendlich C mit wenigen Änderungen. C++ hieß anfangs "C with Classes" (dt. C mit Klassen). Mittlerweile ist es aber viel mehr als das. C++ und C sind unterschiedliche Sprachen. Behalte das im Kopf. Bezüglich Philosophie, beachte auch diese Sammlung von Zitaten von Bjarne Stroustrup, dem C++-Erfinder. Selbst, wenn du deren Inhalt noch nicht gänzlich verstehst, kannst du sehr viel mitnehmen.

    Für gute Listen-Implementation, schaue im Internet, vllt. auf GitHub. Linux hat auch eine Implementation, die du dir der Erfahrung halber gerne anschauen kannst, aber 1. Code enthält, der nicht relevant zum Verständnis verketteter Listen ist und das Verständnis des Codes verkompliziert und 2. in C geschrieben ist. Trotzdem interessant zu sehen, was für Funktionalität implementiert wird, wie dies getan wird und wo sie verwendet wird (Namen sind Links, über die du dich zu verwendeten Stellen "weiterhangeln" kannst).



  • f.-th. schrieb:

    Warum könnt ihr nur Teile des Quelltextes kopieren 😕

    Hast du bei einer Datei nicht so etwas Ähnliches:

    #ifdef JKDLL_EXPORTS
    #define JKDLL_API __declspec(dllexport) 
    #else
    #define JKDLL_API __declspec(dllimport) 
    #endif
    

    😕

    JK soll die Abkürzung für deinen Nick ...

    Und die Header auch bei dem anderen Quelltext?

    Ich habe in meiner .h - datei ein #ifdef , #define, #else. . .
    Wozu benötige ich JKDLL_EXPORTS und JKDLL_API_declspec?



  • Brauchst Du nich. f.-th. schreib seinen Beitrag in der Annahme, Du wolltest eine DLL schreiben.


Log in to reply