Public-Variablen in MFC



  • Hi,
    ich schaue manchmal (nicht so oft 😉 ) im MFC-Forum vorbei und bin dabei darauf gestoßen, dass es dort in ganz vielen Klassen Public-Variablen gibt (z.B. CWnd::m_hWnd). Es ist ja nun allgemein bekannt, dass man keine Public-Variablen verwenden sollte. Warum macht MS dies dennoch, bzw. warum ist die MFC deshalb nicht total verpöhnt?



  • Die MFC ist aus OO-Sicht durchaus verpönt. Allerdings gilt das für die meisten GUI-Libs, diese sind nun mal immer ein Kompromiss aus C++, einer Anbindung an eine C-Schnittstelle und Performanceanforderungen. Und dann kommt noch dazu, daß viele Libs relativ alt sind - die MFC gab's schon unter Win3.11 mit einem Compiler, den man heute kaum noch als C++-Compiler bezeichnen könnte. Aber es ist wirklich so, daß man ein Win3.11-MFC-Programm auch heute noch unter w2k compilieren kann - solche Sachen haben ihren Preis im Aufbau der Lib. Neuere Features wie Templates oder Namespaces sind daher dort gar nicht zu finden. Auch Borlands VCL ist aus ähnlichen Gesichtspunkten (dort der Zwang zur Kompatibilität mit Delphi) an einigen Stellen "haarig". Oder man denke an KDE... wo man einen eigenen Precompiler braucht, um einige Features der Lib so hinzubiegen, bevor man einen C++-Compiler drüber lassen kann.

    Und damit die MFC-Klassen z.B. Dialogeelemente mit den Callbacks aus Windows verheiraten können, müssen einige Dinge eben public sein. Wobei man sagen muß, daß CWnd::m_hWnd sicherlich auch protected angemessen gewesen wäre...

    Dialogklassen sind wegen dieser Zwänge daher nur selten ein schönes OO-Design. Solange man Dialogklassen aber als das betrachtet, was sie sind [Datenliefer- und Anzeigemaschinen für das Programm], tut das nicht wirklich weh - es verursacht keine Schwierigkeiten, wenn man von einer solchen zwanghaft unschönen Dialogklasse seine Daten in durchdachte und designte Workerklassen hinüberschaufelt. Aber was man nie tun sollte: Daten in Dialogklassen verarbeiten. Das Design der Dialogklassen ist ein weiterer Grund für dieses "Don't do that".



  • Hallo,
    darüber läst sich im Rund um-Forum doch viel besser philosophieren.



  • Ja, gibt es denn keine GUI-Lib, die das Herz eines OOP'lers höher schlagen ließe?



  • Wohl keine der "Großen".

    Aber wozu auch?

    Als Teil des Views reicht es für die Dialogklassen durchaus, wenn sie ihren Zweck erfüllen. Großartige Abstraktionen finden dort nicht statt, auch keine Vererbungen und umfangreiche Hierarchiebildungen.

    Im Extremfall ist der View sogar in einer anderen Sprache geschrieben (VB) und hängt über COM am Model/Controller.



  • Original erstellt von WebFritzi:
    Ja, gibt es denn keine GUI-Lib, die das Herz eines OOP'lers höher schlagen ließe?

    gtkmm lässt mein Herz ziemlich hoch schlagen :). Hat ein super Klassendesign. Außerdem ist gtkmm plattformunabhängig (dank Gtk+). Läuft aber unter Windows leider nur mit dem MingW-Compiler.
    fltk soll auch ganz gut sein und läuft problemlos unter Windows auch mit VC++. Hab damit aber noch nix gemacht, bzw. schau mir das gerade an.



  • Original erstellt von palm-man:
    **gtkmm lässt mein Herz ziemlich hoch schlagen :). Hat ein super Klassendesign. Außerdem ist gtkmm plattformunabhängig (dank Gtk+). Läuft aber unter Windows leider nur mit dem MingW-Compiler.
    **

    schon mit windows probiert? ich bin dran gescheitert



  • Ja, hab ich schon gemacht. Bin aber auch dran gescheitert, weil mir dort noch ein paar Libs fehlen. Mit ein bisschen Geduld sollte das aber gelingen ;).
    Ich hab mir gerade die aktuelle Version 2.0 von fltk aus dem CVS geholt und compiliert. Ging ganz problemlos. Ich teste das gleich mal unter Windows.
    ---
    Fertig ;). Zwar funktioniert bei mir die CVS-Version nicht unter Windows, aber die aktuelle stabile Version 1.1 geht wirklich gut mit dem MSVC++. Mein MingW meckert beim Linken. Auch wenns ein bisschen komisch klingt: ich glaub, dem ist die Kommandozeile zu lang :D. Ich hab mich auch nicht direkt an die Readme gehalten, da steht nämlich, dass man noch ein paar Tools aus Cygwin braucht. Das dauert mir aber jetzt zu lange mit meinem 56k-Modem.

    [ Dieser Beitrag wurde am 12.03.2003 um 15:55 Uhr von palm-man editiert. ]



  • ja, gtkmm ist wirklich mal was schönes! (ich muss mal wieder was damit machen, bevor ich wieder alles verlerne :))

    gtk++ soll ja auch sehr schönes OO haben, gtk++ ist aber komplett in C!



  • Zurück zum Ausgangspunkt:

    Die Variablen, die dort public sind sind doch IMHO in den meisten Fällen, die, die das "normale" API Obkekt repräsentieren, was hinter der Klasse steht. Das finde ich eigentlich auch ziemlich sinnvoll, da ich ja z.B., bei jedem Wnd, was ich mit einer API FKT. bearbeitenm möchte jedesmal erst das Fenster suchen müßte.
    Stilistisch nicht unbedingt toll, aber bequem :).



  • Nun ja, ein getHWND() hätte es vielleicht auch getan wenn es um den reinen Zugriff ginge... die wollten wohl hier das letzte Quäntchen Performance rausquetschen.



  • @Marc++us

    class A
    {
      int i;
    public:
      A(int x) : i(x) { }
      inline int geti(void) const { return i; }
    };
    
    struct B
    {
      int i;
      B(int x) : i(x) { }
    };
    
    int main(void)
    {
      A a(1);
      B b(1);
      a.geti();
      b.i;
    }
    

    dürfte doch theoretisch keinen Unterschied geben, von der Performance



  • nicht zu der zeit als die mfc desing wurde, oder?



  • Das ist der Punkt.

    Wie gesagt, die MFC 1.0 wurde noch auf dem alten 16Bit-Compiler übersetzt...



  • HWND ist doch ein Zeiger.
    insofern ist es auch schon fast egal ob man das kapselt, oder nicht (Meyers: returne keine handles auf interne daten)



  • Naja... Zeiger... hm. Darüber kann man hier streiten, da der Zeiger ja nicht wirklich von dem Objekt angelegt wird, sondern aus der WinAPI kommt. Nach Meyer dürfte man damit dann eigentlich überhaupt nicht damit arbeiten...

    Meyer ist ja schön und gut, aber ich kann die Vorgehensweise nachvollziehen - hätten die auf die Rückgabe verzichtet, so hätten in den MFC-Klassen sämtliche API-Funktionen gekapselt werden müssen. So wurden die häufigsten reingenommen und man kann seltene Funktionen weiterhin nutzen.

    Wer mal vom Konzept darüber nachdenkt, wird da einen Gedanken wiederfinden, der aus Sutters Ecke kommt: set-Methoden einmal implementieren und dann außerhalb der Klassen nutzen:

    class Something
    {
    private:
       double m_Value;
    public: 
       void setVal(double value) {m_Value = value;}
    };
    
    void setSomethingValue(Something& something, std::string str)
    {
       double doub = ... aus str; 
       something.setVal(doub);
    }
    

    Also Klassen schlank halten und kleine Schnittfläche des Interface realisieren. Die Idee hier ist nicht so unähnlich.

    Man muß es so sagen: die MFC ist alt - softwaretechnisch eindeutig veraltet. Aber sie ist nicht dumm. Denkt man an schlecht optimierende C++-Compiler und eine fehlende STL zurück, so ist die MFC unter diesen Randbedingungen gar nicht so schlecht. Wer noch die OWL kennt, wird die gleichen Rahmenbedingungen und gleiche Lösungswege auch von Borland finden.

    Dumm nur, daß man eben diese Altlasten immer noch mitschleppt. Das ist aber eine politische Entscheidung - will man das tun oder nicht. Das ist aber eine andere Diskussion.



  • Wie schaut dass eigentlich bei den .Net APIs und C# aus? Sind die hier konsequenter als bei der MFC?



  • Die würde ich als State of the Art bezeichnen. Ich denke mal das Design der .NET-API ist der Hauptgrund, warum überhaupt Leute versuchen das Ding unter Linux zum laufen zu bekommen - wg. der VM sicherlich nicht. Und wg. C# alleine auch nicht.

    Wenn Du die VCL von Borland kennst, werden Dir gerade bei den GUI-Klassen (wobei .NET ja noch mehr hat außer GUI) die Klassen und Methoden relativ bekannt vorkommen.

    Wer VCL kennt, wird .NET lieben... oder so ähnlich. 😉



  • Original erstellt von Marc++us:
    Wer VCL kennt, wird .NET lieben... oder so ähnlich. 😉

    Hört sich gut an. 🙂


Anmelden zum Antworten