Klassenfrage :)



  • @omggg
    ok, danke



  • @SeppJ Ichversuch mal deinen Code zu beschreiben
    in der Klasse Caller
    wird mit "void (foo.." ein Zeigerobjekt auf irgendeine Methode der Klasse Foo angelegt,
    und mit "std::func.."eine std::function mit dem namen "bound_member" und dem Rückgabewert void deklariert.
    Dann unter public folgt der Konstruktor von Caller dem zwei Parameter und dazu zwei ppassende Standartwerte übregeben werden? Und in der Methode call() wird "einfach" auf den Konstruktor von Foo zugegriffen um dann über das Objekt f.*unbound_foo_member auf eine in den Konstrutionsparametern übergebene Funktion in Foo zugreifen zu können und dann wird die std::function bound_member aufgerufen.

    Wenn das stimmt ist das mir zu Abtrakt um es auf Apfel und Wurm übertragen zu können.
    Kannst du bitte den Konstruktor von Caller( wenn es den überhaupt einer ist) und die "Schritte" in main näher erläutern


  • Mod

    Da, ganz ohne drumherum.

    #include <iostream>
    #include <functional>
    
    
    using namespace std;
    
    
    class Foo
    {
    	int i;
    public:
    	Foo(int i) : i(i) {}
    	void func1() { std::cout << "Func 1 von Foo(i=" << i << ")\n"; }
    };
    
    
    int main()
    {
    	Foo f(456);
    	std::function<void()> bound_func1 = [&f] {f.func1(); };
    	void (Foo::* unbound_func1)() = &Foo::func1;
    	
    	bound_func1();
    	(f.*unbound_func1)();
    }
    

    Den Caller hatte ich doch nur gezeigt, weil du dich so daran aufgehangen hattest, dass das unbedingt in einer Klasse sein müsse, als ob da dran irgendetwas besonderes wäre.



  • @SeppJ
    Ich hab eine einfache Frage ja auch kompliziert gestellt, und versuch jetzt erstmal die Übertragung deines Codes


  • Mod

    @EL-europ sagte in Klassenfrage 🙂:

    @SeppJ
    Ich hab eine einfache Frage ja auch kompliziert gestellt, und versuch jetzt erstmal die Übertragung deines Codes

    Nein! Werd' lieber dein Design los, das dich denken lässt, dass dies überhaupt nötig wäre! Du übersiehst garantiert irgendwas simples, das schon in der Sprache eingebaut ist. Dazu musst du natürlich erst einmal die Sprache besser lernen. Aber das wäre was gutes, denn man sollte schließlich die Sprache beherrschen, die man spricht.



  • @SeppJ
    Mir fällt nix besseres ein. Ich müsste ja eigentlich eine "abstrakte" Klasse definieren von der ich Apfel und Wurm gemeinsam ableite; Wenn ich den oop-ansatz richtig verstehe?


  • Mod

    @EL-europ sagte in Klassenfrage 🙂:

    @SeppJ
    Mir fällt nix besseres ein. Ich müsste ja eigentlich eine "abstrakte" Klasse definieren von der ich Apfel und Wurm gemeinsam ableite; Wenn ich den oop-ansatz richtig verstehe?

    Da wird ja gerade der Designfehler sein, denn das klingt offensichtlich falsch. Aber mit dem Apfel-Wurm-Beispiels kommt man da nicht weiter, weil da in der echten Welt keine tiefergehenden Beziehungen existieren, als das beides physikalische Objekte sind, und das ein Apfel einen oder mehr Würmer haben kann. In der echten Welt wird der Apfel nie etwas mit einem Wurm machen, und die Würmer werden eventuell etwas aus dem umgebenden Apfel fressen. Nichts davon klingt auch nur entfernt nach Übergabe von Memberfunktionszeigern..



  • @SeppJ Nun ja aber:
    Die Beziehung "Apfel->schrumpf() wenn Apfel->Wurm->friss()" ist gegeben.
    Aber du hast Recht, ich sollte zumindest die entsprechenden Kapitel noch mal lesen. Bis dahin 🙂


  • Mod

    Ist ein bisschen komisch, dass der Apfel sich von dem Wurm fressen lässt, aber naja, nehmen wir das mal als gegeben an, weil die Analogie vielleicht nicht perfekt ist. Aber wieso muss in dem Fall an Wurm::friss die Methode Apfel::schrumpf übergeben werden? Sollte nicht die Fressmethode wissen, dass sie den Apfel schrumpfen soll?

    class Wurm
    {
        void friss(Apfel &zu_fressender_apfel)
        {
            ...
            zu_fressender_apfel.schrumpf();
            ...
        }
    };
    

    Oder ist die Sache, dass der Wurm auch in anderem Obst sein kann? Dann wäre das, wie spekuliert, ein Fall für virtuelle Methoden:

    class Obst
    {
        virtual void schrumpf();
    };
    
    class Apfel: public Obst
    {
        virtual void schrumpf() {wie ein Apfel schrumpft;}
    };
    
    class Birne: public Obst
    {
        virtual void schrumpf() {wie eine Birne schrumpft;}
    };
    
    class Wurm
    {
        void friss(Obst &zu_fressendes_obst)
        {
            ...
            zu_fressendes_obst.schrumpf();
            ...
        }
    };
    

    Da wird dann in friss automatisch an die passende schrumpf-Methode verwiesen, je nachdem, welches Obst der Wurm frisst.

    Im Hintergrund arbeiten dann zugegebenermaßen Memberfunktionszeiger. Aber das macht halt die Sprache für dich als Feature, und du musst dich nicht mit solch fehleranfälligem Zeug mit komischer Syntax herumschlagen. In C muss man das halt selber machen, wenn man diesen Effekt will, daher hatte ich die Vermutung, dass das hier die Richtung ist, aus der du kommst.



  • Danke @SeppJ
    Ich habs über std::function hinbekommen die Methode aufzurufen, jetzt kann ich den restlichen Code erstma debuggen 😋



  • @EL-europ sagte in Klassenfrage : ):

    Und werde die entsprechenden Kapitel in Jürgen Wolf's c++11 lesen. Oder gibt es eine Onlninefom die vielleicht sogar besser ist.
    Herr Wolf ist in diesem Buch immer sehr theoretisch mit seinen Beispielen.

    Du hast den schlechtesten Autor für C++ erwischt: WARNUNG: Bücher von Jürgen Wolf zu C und C++ zum Lernen ungeeignet weil....

    Wenn du englisch beherrschst, dann verwende LearnCpp.


  • Mod

    Ojeh, das hatte ich ganz überlesen. Das erklärt die komisch klingenden Designprobleme. Laut Jürgen Wolfs Designbeispielen ist ein Supermarkt schließlich ein Wurstbrot. Nein, das ist kein Scherz.



  • @Th69 Danke für den Link



  • @SeppJ @Th69
    Ich glaube Herrn Wolf fehlte damals (als er die Bücher schrieb) einfach die Praxis, also nicht "Programmierpraxis" sondern Berufspraxis. Seine Beispiele lesesn sich wie von einem Schüler dessen Lebensmittelpunkt die Schule ist. Es sind seit dem "c++11" schon Jahre vergangen, und zu hoffen das Jürgen Wolf seine Prxis erweitert hat und in Bücher einbringen wird ist berechtigt.


  • Gesperrt

    Hm, nur weil in einem Beispiel ein Supermarkt ein Wurstbrot ist... sollte man ihm vielleicht nicht jegliche Fähigkeiten absprechen, geradeaus zu denken... Denn das Supermarktbeispiel ist total irrelevant... wichtig sind die Paradigmen.



  • @omggg sagte in Klassenfrage 🙂:

    Denn das Supermarktbeispiel ist total irrelevant... wichtig sind die Paradigmen.

    Bitte was? So ein Buch sollte vermitteln, dass man sinnvolle Datenstrukturen aufbaut, die man nachvollziehen kann. Wenn man modelliert, dass ein Wurstbrot ein Supermarkt ist (zum Glück nicht "isst", aber warum eigentlich nicht, im Supermarkt gibts Nahrungsmittel, also kann man doch einen Supermarkt auch essen - ist dieselbe Logik...), dann ist Hopfen und Malz verloren. Das war ja auch nur ein Beispiel von dem Mist, der in dem damaligen Buch stand. Vielleicht ist das neue Buch besser. Wer weiß. Zu befürchten ist, dass so offensichtliche Dinge behoben sind, aber man es generell trotzdem nicht nutzen sollte.

    Ich sag mal so: ich hatte mal einen Kollegen, der dieses Buch zum Lernen verwendet hatte. Er war nur wenige Monate mein Kollege.



  • @wob sagte in Klassenfrage 🙂:

    Ich sag mal so: ich hatte mal einen Kollegen, der dieses Buch zum Lernen verwendet hatte. Er war nur wenige Monate mein Kollege.

    Kann dieses Zitat jemand in die Warnung vor seinen Büchern mit einbauen?

    Danke.


  • Gesperrt

    @wob

    Ach herrje, ich hab den Wolf mit dem Breymann verwechselt ... Ich muss aber dazu sagen, dass ich beide Bücher nicht zur Gänze gelesen habe ... insofern kann ich mir kein Urteil anmaßen.

    Aber mal Butter bei die Fische ... ist Vererbung, also genauer gesagt das Decorator pattern, nicht einfach nur syntaktischer Zucker? Heikle These, das stimmt, aber hier werden auch Alternativen genannt: https://en.wikipedia.org/wiki/Inheritance_(object-oriented_programming)#Issues_and_alternatives

    kurz: Rollen!



  • @wob @omggg
    Als Anwender lernt man c++ weil man was programmieren will, nicht um eine akademische Auseinandersetzung über Klassendesing führen zu können. Der Vorwurf gegen Jürgen Wolf mit seinem Handbuch zu c++, das OOP-Thema (Von dem ich selbst erfolgreich nicht viel verstehe) unzureichen behandelt zu haben, scheint mir trivial in Abetracht eurer Kritik 😃



  • @EL-europ sagte in Klassenfrage 🙂:

    Als Anwender lernt man c++ weil man was programmieren will, nicht um eine akademische Auseinandersetzung über Klassendesing führen zu können. Der Vorwurf gegen Jürgen Wolf mit seinem Handbuch zu c++, das OOP-Thema (Von dem ich selbst erfolgreich nicht viel verstehe) unzureichen behandelt zu haben, scheint mir trivial in Abetracht eurer Kritik

    Dann tu, was du nicht lassen kannst.

    Eine Recherche von 15 MInuten lieferte mir aber schon folgende Dinger:

    Insbesondere die explizite Typumwandlung per reinterpret_cast und der dynamic_cast sind ein relativ kompliziertes und weitreichendes Thema. Sie werden daher an dieser Stelle nicht weiter behandelt.

    Quelle: "Grundkurs C++", 2021

    Das erklärt sich, so glaube ich, von selbst. Und ein Zeilen später wird der C Cast erklärt und dass dieser gefahrlich ist. Kein Beispiel warum.

    struct Programm
    {
    	DatabaseInterface &db_:
    	
    	void run()
    	{
    		std:: cout << db_.getData() << "\n";
    	}
    }
    

    Quelle: C++: "Das umfassende Handbuch zu Modernen C++. Über 1.000 Seiten Profiwissen aktuell zum Standard C++20"

    Kein Wort zum Thema Lebenszeiten, dass jede Programm Instanz an die Lebenszeit von db_ gebunden ist und dies eigentlich ein gefährlicher Programmierstil ist.