Klassen: privat Funktion/Variable "verstecken"



  • @all Brauche Bestätigung. Würde folgendes Funktionieren?
    Im Schlaf liegt Segen. Über Nacht kam mir vermutlich eine "regelkonforme" Lösung.

    Also, an anderer Stelle hier im Forum habe wurde mir ja bereits bestätigt, daß ich auch mehr als eine Headerdatei haben kann.
    Welche Konsequenzen hätte es, wenn ich für jede Klasse 5 Headerdatein schreibe, oder wäre das eine "gute" Lösung.

    • In der >KlassenHeader.h< steht dann Regelkonform die vollständige Klasse, alles von Public bis "hiden". Dieser >KlassenHeader.h< wäre dann exklusiv für die >Klassen.cpp< und wird nirgendwo anders im Programm genutzt.

    • Die >Klassen.h< hingegen darf mit #include in jede .cpp eingebunden werden, enthält jedoch nur den Public-Teil der Klasse.

    • Die >KlassenZeiger.h< ist "leer":

    class Klasse {};
    //Wird verwendet wenn eine .cpp nur Zeiger auf die Klasse benötigt.
    
    • Analog dazu enthält >KlassenProtected.h< neben dem public Teil auch alles was als protected eingestuft wurde.

    • In >KlassenPrivate.h< fehlt dann nur noch was exklusiv intern für die Klasse gedacht ist und ich darum "hiden" haben möchte.

    @Belli
    Dies mag jetzt vielleicht für manchen wie eine faulen Ausrede klingen, aber anders als bei euch, erscheint mir der Compiler kein zuverlässige Quelle. Wenn hier im Forum jemand etwas sagt, dann ist das auch so, den würde er sich irren, käme sofort ein anderer, der ihn richtig stellt.
    Die Reaktion des Compiler kann jedoch viele Gründe haben, erstmal muß ich unterscheiden ob eine Fehlermeldung bedeutet "geht nicht" oder "tippfehler", wenn es kein "tippfehler" ist, sagt er nur "so geht es nicht", er wird mir niemals vorschlagen, was ich anders machen könnte, er wird mir auch niemals sagen, so funktioniert es, aber dies und das wäre eine besser Möglichkeit und zu guter letzt bedeute das fehlen einer Fehlermeldung keines wegs das ich alles richtig gemacht habe, sondern nur das es dem Compiler jetzt egal ist, kann aber trotzdem noch dazu führen, daß das Programm etwas anderes tut als das was ich tatsächlich will.

    Nachtrag: Während ich obiges geschrieben habe, wurde mir "PImpl Idiom" empfohlen. Klingt auf den ersten Blick durchaus vielversprechend, muß ich mir jedoch erst noch im Detail genauer ansehen.



  • @axam sagte in Klassen: privat Funktion/Variable "verstecken":

    Welche Konsequenzen hätte es,

    Es wäre falsch. Stichwort One Definition Rule



  • Und was @manni66 mit "falsch" meint ist: es ist explizit vom C++ Standard verboten, Stichwort "one definition rule".
    (Der Term "falsch" war da schon korrekt verwendet, ist also keine Korrektur. Ich wollte nur klarstellen dass er nicht frei im Sinn von "wir finden das furchtbar und nennen es deswegen falsch" verwendet wurde.)

    (EDIT: War der Link zur "one definition rule" immer schon in @manni66 s Beitrag? Wenn ja hab ich wohl nach "Es ist falsch" aufgehört zu lesen und mein Hirn ausgeschaltet. Hmmm...)

    Deine KlassenZeiger.h Idee ist umsetzbar, aber nicht so wie du es geschrieben hast. Korrekt verwendet man dazu eine sog. "forward declaration", und die sieht so aus:

    class Klasse;
    


  • @hustbaer sagte in Klassen: privat Funktion/Variable "verstecken":

    (EDIT: War der Link zur "one definition rule" immer schon in @manni66 s Beitrag? Wenn ja hab ich wohl nach "Es ist falsch" aufgehört zu lesen und mein Hirn ausgeschaltet. Hmmm...)

    Nein, ich habs kurz vor deinem Post ergänzt.



  • @manni66
    Danke. Dann bin ich mal beruhigt 🙂
    Ich bin zwar von Haus aus schusselig, und jünger werde ich auch nicht, aber das übersehen zu haben hätte ich dann schon etwas krass gefunden.



  • Danke erst mal für die hilfreichen Antworten.

    Und danke für den Hinweis mit "class Klasse;" anstelle von "class Klasse {};".
    Eun gutes beispiel dafüur, warum ich euch hierim Forum Frage und nicht den Compiler.
    Der Compiler würde mir in dem Fall nur sagen "geht nicht", das es jedoch "nur" falsch geschrieben ist, merke ich erst, wenn ich bereits weiß das es eigentlich Funktionieren sollte und darum den Fehler suche, anstatt einfach anzunehmen es sei grundsätzlich "falsch".

    Was jedoch die Sache mit den Headerfiles/"OneDefinitionRule" betrifft, ist mir das Ganze jedoch immer noch ein wenig unklar (zumal ich selbst schon bei deutschen Texten so manches falsch verstehe).

    Zitat: In general, a translation unit shall contain no more than one definition of any class type. In this example, two definitions of the class type C occur in the same translation unit. This typically occurs if a header file is included twice by the same source file without appropriate header guards.

    Möglicherweise wurde meine Überlegung ja einfach nur missverstanden....Edit: Fehler Erkannt =daher=> unwichtige dumme Erklärung gelöscht:

    @axam sagte in Klassen: privat Funktion/Variable "verstecken":
    Möchte mich jetzt mal bei allen hier entschuldigen.
    Man sollte immer erstmal denken bevor man spricht.



  • Ein simples Beispiel um das mit der Deklaration und der einmaligen Definition zu erklären.

    // example.h
    class Example {
        int value_;
    public:
        Example (const int value);
        int getValue() const;
    };
    

    Und die dazu gehörende Implementation.

    // example.cc
    Example::Example (const int value) : value_ (value) {}
    
    int
    Example::getValue () const {
        return value_;
    }
    

    In der Datei example.cc stehen nun die Definitionen für den Konstruktor und für eine member function getValue.



  • @axam sagte in Klassen: privat Funktion/Variable "verstecken":

    Möglicherweise wurde meine Überlegung ja einfach nur missverstanden.

    Nein! Eine Klassendeklaration ist auch eine -definition. Die muss im gesamten Programm gleich sein.



  • @manni66 sagte in Klassen: privat Funktion/Variable "verstecken":

    Nein! Eine Klassendeklaration ist auch eine -definition.

    ?

    class test;
    


  • @Belli sagte in Klassen: privat Funktion/Variable "verstecken":

    @manni66 sagte in Klassen: privat Funktion/Variable "verstecken":

    Nein! Eine Klassendeklaration ist auch eine -definition.

    ?

    class test;
    

    Forward declaration



  • @manni66
    Ich glaube hier gibt es eine kleine Begriffsverwirrung.
    Das:

    class Foo {
    public:
        int bar();
        int baz();
    };
    

    ist eine vollständige Klassendefinition. Bloss die Member-Funktionen sind noch nicht definiert (aber bereits deklariert).



  • @axam Dein Hauptproblem ist, daß Du kein aktuelles Lehrbuch hast. C++ innerhalb eines Forenthreads zu vermitteln ist zum Scheitern verurteilt.

    // edit: blubb.

    // edit 2: @john-0 Du hast nicht verstanden ab wann eine Klasse definiert ist. +1 für @hustbaer ;

    @axam Vielleicht möchtest Du mal erklären was Du überhaupt erreichen möchtest? Visibility sollte nach meinem Link oben ja hoffentlich klar sein?



  • @axam
    Die Definition einer Klasse muss immer und überall (im ganzen Programm) gleich aussehen. Nicht auf den Buchstaben genau gleich, aber sie muss äquivalent sein. (Die genauen Regeln dazu welche Unterschiede erlaubt sind und welche nicht sind kompliziert und selten hilfreich, am besten gehst du davon aus dass jeder Unterschied verboten ist.)

    Und weiters gibt es noch die Regel dass eine Klasse pro Translation Unit nur 1x definiert werden darf. Das ändert aber nichts an der ersten Regel: wenn du 2 Translation Units hast, darf die Klasse natürlich pro TU 1x definiert werden, aber diese Definitionen müssen wie gesagt äquivalent sein.

    Das ist im übrigen auch ein Fehler den dir der Compiler nicht mitteilen wird. Also wenn du in zwei verschiedenen Files die selbe Klasse unterschiedlich definierst, dann kann es leicht sein dass du keine Fehlermeldung bekommst, dafür aber ein Programm das undefiniertes Verhalten hat. Also z.B. falsch rechnet oder abstürzt oder halt einfach irgendwas macht.



  • Möchte mich jetzt mal bei allen hier entschuldigen.
    Man sollte immer erstmal denken bevor man spricht.
    Hab mich da irgend wie in einen unsinnigen Gedanken verrannt, und mir ist inzwischen auch selbst klar geworden, warum soetwas nicht gehen kann und daß dies zu nichts führt.

    Trotzdem vielen Dank.
    Alerdings war dieses threat für mich dennoch sehr nützlich, denn vermutlich ist "PImpl Idiom" genau das, was ich gesucht habe.
    Zudem ist mir klar geworden, daß ich (geistig) nicht den Fehler machen darf eine Klasse mit .cpp und .h zu assoziieren (was jetzt im Nachhinein auch logisch ist, da mir ja bereits bekannt war, das ich ein Klasse auch direkt in die main.cpp schreiben könnte).

    Und @john-0, ein aktuelles Lehrbuch hätte mir bei meinem letztgenannten Denkfehler wohl auch nicht weiter geholfen, schließlich habe ich bereits dutzende Erklärungen gelesen, und mir ist trotzdem erst jetzt klar geworden, das ich von falschen Annahmen ausgehe.
    Werde mir jedoch in Zukunft etwas mehr Zeit lassen, bevor ich "dumme" fragen stelle, den wenn man erstmal eine Nacht darüber schläft, sieht die Welt plötzlich ganz anders aus.



  • @Swordfish sagte in Klassen: privat Funktion/Variable "verstecken":

    // edit 2: @john-0 Du hast nicht verstanden ab wann eine Klasse definiert ist. +1 für @hustbaer ;

    Wie immer ist es erbauend, wenn man einen Fehler in der Beschreibung gemacht hat, dass einem das notwendige Wissen abgesprochen wird.

    Also noch einmal sprachlich präzise.

    // example.h
    class Example; // Eine reine Deklaration einer Klasse, aber außer für opaque Zeiger vollkommen nutzlos.
    
    // Definition der Klasse, bis auf die member functions
    // Eine Definition kann nachher nicht mehr erweitert werden,
    // d.h. alle member müssen bei der Definition angegeben werden.
    // Nur member functions können später definiert werden.
    class Example {
        int value_;
    public:
        Example (const int value);
        int getValue () const;
    };
    
    // example.cc
    Example::Example(const int value) : value_ (value) {}
    
    int
    Example::getValue () const {
        return value_;
    }
    

    Wenn man stattdessen eine Template definiert, müssen die member functions auch direkt mit definiert werden. (Deshalb @hustbear würde ich nicht von einer vollständigen Definition reden, wenn die member functions nicht auch definiert wurden.)

    //example_template.h
    template <typename T>
    class Example {
        T value_;
    public:
        Example (const T& value) : value_ (value) {}
        T getValue () const {
            return this->value_;
        }
    }; 
    

    Nur Spezialisierungen können in einer eigenen Übersetzungeinheit definiert werden.

    Kommen wir zum eigentlichen Problem zurück. C++ erlaubt es nicht, die Definition einer Klasse später zu erweitern. D.h. die Klasse ist immer komplett sichtbar, aber member oder member functions sind nicht zugreifbar, wenn sie mit private oder protected geschützt sind. Das ist dann ein Problem, wenn man Implementationsdetails verstecken will. In C++ geht das im Gegensatz zu anderen OOP-Sprachen nicht, so dass man hier zum Proxy-Pattern bzw. Bridge-Pattern (auch PImpl-Idiom genannt) greifen muss.



  • @john-0 sagte in Klassen: privat Funktion/Variable "verstecken":

    // Definition der Klasse, bis auf die member functions

    Ja ne, eben nicht. Die Klasse ist definiert. Ich weiß nicht was der Halbsatz dahinter soll.



  • @Swordfish sagte in Klassen: privat Funktion/Variable "verstecken":

    Ja ne, eben nicht. Die Klasse ist definiert. Ich weiß nicht was der Halbsatz dahinter soll.

    Die Klasse ist nur formal definiert. Es geht gerade bei Anfänger darum zu vermitteln wie der Code korrekt zu organisieren ist. Die Member Functions können in einer Übersetzungseinheit separat definiert werden, aber sie können auch als Teil der Klassendefinition definiert werden. Was dann zum nächsten Problem führt, dass die One-Definition-Rule sich nur auf die Übersetzungseinheit bezieht und die Norm explizit erlaubt, dass N gleiche Kopien einer Klasse existieren – in N verschiedenen Übersetzungseinheiten. Womit der Linker wieder viel Arbeit bekommt.



  • Funktionen und Variablen Berechnungen zu programmieren finde ich noch immer eine der spannendsten Aufgaben. Vermutlich, weil ich Mathematik auch so gerne habe! 🤣


Anmelden zum Antworten