Was würdet Ihr an C++ ändern, wenn Ihr keine Rücksicht auf Kompatibilität, Geld, Zeit, Arbeit, etc. nehmen müssten?



  • Halt je nach verwendung.

    X ist X-Server.
    Beim Compilieren des X-Server werden zum teil so viel schrott
    noch auf das system geworfen, das man die sicherheits risiken
    nicht mehr greiffen kann.

    Unter dem Motto "Wer auf dem Netz Arbeitet muss Hacken koennen"
    hab ich sachen gesehen, die mir die Haare zuberg stehen liesen.
    Darum, nur wer solches sieht kann verstehen, wieso ICH
    unter UNIX Arbeite.

    Darum, jeder das welches er braucht.
    Ich wollte eigentlich keine solche schlammschlacht fabrizieren.
    Sorry an die ich gestoert habe,
    und ich hoffe das ich hier noch etwas geduldet bin.

    Ghost



  • - ich habe leichte Probleme mit deinen Sätzen. Vielleicht kannst Du sie vor dem abschicken ja nochmal durchlesen. Danke -

    Green_Ghost schrieb:

    X ist X-Server.
    Beim Compilieren des X-Server werden zum teil so viel schrott noch auf das system geworfen, das man die sicherheits risiken nicht mehr greiffen kann.

    Kannst Du das mal näher ausführen, was die unfaßbaren Risiken von X11 so sind?



  • um mal back2topic zu kommen:

    2 sachen die ich mir sehr wünsche:

    schauen ob ein beliebiger typ T public von typ Foo geeerbt hat

    zb so:

    template<class T>
    void bar(const T& a:public Foo){
        //benutze spezielle funktionen die genau auf diese art von typen zugeschnitten sind
    
    template<class T>
    class Bar{
        //normales zeugs
    };
    template<class T>
    class Bar<T:public Foo>{
       //spezielles zeugs für Klassen die von Foo abgeleitet sind
    };
    }
    

    vorteil: ich kann funktionen/klassen besser auf bestimmte typen optimieren

    2. punkt
    überladen von funktionen/methoden auch auf wertbasis

    wieso das?

    nun, manchmal kommt es vor, dass das verhalten einer funktion/methode von dem übergebenen objekt/der klasse abhängig ist, je nachdem welchen status dieses objekt hat, verhält sich die funktion/klasse dann anders.

    Vielleicht kann man hier ja das Reinforcement-learning als Beispielanführen, wies hier vorgestellt wird.

    soweit ich das verstanden hab, versucht dabei ein Agent aus dem objekt status+einem input eine aktion zu generieren. Diese aktion wird dann ausgeführt und verändert den status des objekts. beim nächsten aufruf des agents muss er sich dann der neuen begebenheit anpassen.

    und da könnte man ja ansetzen, indem man für bestimmte werte dem agent ein anderes verhalten oder ein optimiertes verhalten gibt.

    normal würde man das vielleicht so machen:

    //agent funktion
    action agent(const int status, const input& input){
        switch(status){
            case 0:
               //sonderfall status 0
            break;
            case 1:
               //sonderfall status 1
            break;
            default:
               //normales verhalten
        }
    }
    

    wärs nicht übersichtlicher, dass einfach so zu machen?

    action agent(const int status, const input& input){
        //normales verhalten
    }
    action agent(const int status where status=0, const input& input){
        //sonderfall status 0
    }
    action agent(const int status where status=1, const input& input){
        //sonderfall status 1
    }
    

    klar, syntaktisch ist das nochnicht ganz ausgereift, aber der vorteil an der sache ist, dass der code einfach erweitert werden kann, wenn sich bei der status verarbeitung was ändert, man fügt einfach hinzu. 👍

    vielleicht könnte man auch sowas machen?

    class Foo{
        private:
            int status;
        public:
            void doSth()const {
                //mach irgendwas
            }
            void doSth() const where status=1{
                //tu was anderes
            }
            void changeStatus(int);
    };
    

    wie gesagt, sind nur küne vorschläge die einfach an bestimmten stellen nützlich sein können(1. punkt wohl eher als letzterer).



  • Daniel E. schrieb:

    - ich habe leichte Probleme mit deinen Sätzen. Vielleicht kannst Du sie vor dem abschicken ja nochmal durchlesen. Danke -

    Green_Ghost schrieb:

    X ist X-Server.
    Beim Compilieren des X-Server werden zum teil so viel schrott noch auf das system geworfen, das man die sicherheits risiken nicht mehr greiffen kann.

    Kannst Du das mal näher ausführen, was die unfaßbaren Risiken von X11 so sind?

    Etwas Muede, Sorry.

    So mein letzter Post zu diesem Thema.

    Erstens ist die Frage, ob es auf einem Mailserver eine X geben muss.
    Dann ist der X Port auch nicht ungefaehrlich.
    Je nach X-Umgebenung, werden Programme installiert, deren
    sicherheit du nicht immer abschaetzen kannst.
    Ich hoffe dies Beantwortet deine frage.

    Gehe schlafen. Wie gschrieben, mein letzter Post zu diesem Thema.
    Ich will mich hier ja noch blicken koennen.

    Ghost



  • Shade Of Mine schrieb:

    Green_Ghost schrieb:

    Aber ich verstehe, das mich keiner von den Windows User verstehn kann.
    Und ab und zu Etwas Linux, ist auch Windows 😉

    [...]

    Du siehst also: ob Windows oder Linux ist absolut egal.

    [...]

    In dem Sinne: every OS sucks

    👍 👍 👍 👍

    Endlich mal jemand der das ganze unfreakisch aus der Sicht eines Normalanwenders sieht.
    Es ist so absolut egal was auf der Kiste läuft Hauptsache es läuft überhaupt. Office,
    surfen, mailen, programmieren - wen interessierts was drunter läuft, solange ich machen
    kann was ich brauche? Es gibt wichtigers/schöners im Leben außer missionarisch für
    irgendwelche Betriebssysteme zu werben.

    BTT, denn das ist wirklich interessant.



  • otze schrieb:

    2. punkt
    überladen von funktionen/methoden auch auf wertbasis

    Das sieht mir nicht wirklich sinnvoll aus.
    Die Lösung mit dem switch ist natürlich inakzeptabel.

    Was aber spricht gegen ein functionMap[inputValue](); ?
    Das ganze kannste genau hinter der Schnittstelle verstecken und es ist nicht wirklich aufwendig das zu machen. Ein paar Zeilen genügen ja schon. Außerdem kannste so die Methoden sogar nach Bedarf zur Laufzeit noch austauschen.

    Da sieht ersterer Vorschlag sinnvoller aus. Obwohl man auch das bereits jetzt relativ gut hinkriegt. Zugegeben: Der Code ist nicht ganz so lesbar.

    MfG Jester



  • Ich mus Jester wiedersprechen. Das ganze ist sogar sehr sinnvoll. Allgemein findet man sowas unter dem Namen Prädikat Methoden. Das gab's schon als Erweierung zu diversen Sprachen (z.B. JPred als Java-Erweiterung, ...).
    Da natürlich deutlich ausgefuchster, als der hier gebrachte Vorschlag.
    Den ersten Teil findest du dort ebenfall als Teil der Prädikate.

    Nein, eben nicht wie in C. Die Strings sind in D objektorientiert und haben Methoden. Sie sind eben nicht nur arrays of char. Auch wenn sie so aussehen und man sie so benutzen kann.

    Jeder Typ, selbst int hat in D "Methoden", (z.B. init). Dadurch ist es aber keinesfalls Objektorientiert. Objektorientierung entsteht nicht dadurch, dass es die Punkt-Syntax gibt. Guck dir z.B. mal Dylan, CLOS oder auch Nice an, damit du vielleicht erkennst, dass die Synthax nichts mit OO zu tun hat.

    Intern werden sie nämlich als Reference-Typs mit einem Stringpool verwaltet. Ein char[] funktioniert ganz anders als ein int[], float[] usw ...

    Falsch. COW (copy on write) gibt es überall in D.

    Walter (der Erfinder von D) ist da immer was eigen. Er sieht alle Dinge immer sehr technisch und nicht so abstrakt, wie es heutzutage üblich ist. Er sagt, ein String ist nur eine Kette von Zeichen, als werden sie in D auch genau so behandelt. (Beinahe ein wörtliches Zitat, nur eben auf Englisch.)
    Deswegen gibt es auch keinen Boolean-Typ (jetzt komm mir nicht mit dem alias auf bit). Er sagt, ein Bool'scher Typ ist ein Typ, der zwei Zustände annehmen kann, also passt bit hier perfekt. Soetwas, wie nur true ist auch wirklich wahr, wie man es in den heutigen Sprachen hat (Java, C#, ...) gibt es nicht.
    Natürlich erkennt er, dass man mit dem sonst üblichen Verhalten den häufigen Fehler von Zuweisungen statt Vergleichen in if-Konstrukten verhindert, aber das löst er ganz anders, indem er einfach Zuweisungen im if verbietet.

    Ich habe nie gesagt, dass die Art, wie D mit Strings umgeht schlecht sei. Aber es gibt keine Stringklasse.

    Ließ dir doch einfach mal alte Diskussionen zu dem Thema durch, wie z.b. diese.



  • Ein bischen geflame macht immer Spaß, als mach ich doch einfach mal mit:

    Ich rede hier von der NO-X umgebung (SHELL)
    X-Server ist ne spielerei, und je nach dem nur gebrauch bar.

    Was ist mit Dingen, wie Bildbearbeitung (Grafiken fürs Web, Plakatwerbung, ...), oder einfache Textbearbeitung (Zeitschriften, Bücher, ...), Musikproduktion (CDs, Radio, Filmmusik, ...), CAD/CAM (Design von Autos, ...). Das wird alles in grafischen Oberflächen gemacht, da es anders nicht sinnvoll machbar ist. Und das ist alles nur Spielerei?

    Ich glaube darüber solltest du nochmal nachdenken.



  • Ich würde break in Switch-Statements abschaffen und am Ende jedes Case automatisch rausspringen 😃



  • Jester schrieb:

    Da sieht ersterer Vorschlag sinnvoller aus. Obwohl man auch das bereits jetzt relativ gut hinkriegt. Zugegeben: Der Code ist nicht ganz so lesbar.

    nicht ganz richtig.
    es gibt 2 techniken um die vererbung rauszukriegen:

    die erste basiert auf konvertierung von zeigern. Die andere versteh ich nicht 😃

    die erste Möglichkeit hat einen großen Haken:

    class Foo:Bar{};
    

    versuchst du einen Foo* nach Bar* zu konvertieren, schmeisst der compiler nen error->also unbenutzbar.

    die zweite Möglichkeit schafft zwar alle Arten der Vererbung, liefert aber auch keinen Anhaltspunkt darauf, ob public vererbt wurde.



  • PCfreak schrieb:

    ich würde das gnaze übersichtlicher machen und perfekt auf deutsch übersetzten

    Aber es vorher bitte lernen!



  • @asdrubael: super Idee, und dafür dem continue statement in einer switchanweisung semantik einräumen.
    @otze:
    Versteh ich nicht.

    template<class T,U>
    struct inherits
    {
    private:
        struct big{char[2];};
        typedef char small;
        T create_t();
        small test(...);
        big test(const U&);
    public:
        enum{inherits=sizeof(test(create_t()))==sizeof(big)};
    };
    

    Da wäre noch das Problem, dass hier auf implizite Konvertierung getestet wird, und publicvererbung nunmal die geläufigste ist.
    Wie sieht das 2. aus?



  • Was otze da beschreibt sind eine Form von Multimethods. Die gibts in C++ nicht und alle mir bekannten Wege Multimethods nachzubauen sind zu umständlich, um sie einfach so mal eben zu benutzen. Aber nur dann werden sie in der Regel interessant.
    Auch das Visitor-Pattern wird komplett überflüssig, wenn solche Multimethods vorhanden sind.



  • Ein Beispiel für eine Anwendungsmöglichkeit:

    // Vorgabe
    class BasicEventhandler {
       void handle (Event const & event)
       {
          throw UnknowEvent ();
       }
       void handle (Event@IrgendeinStandardEvent const & event)
       {
          // Behandlung
       }
    };
    
    // selbstgeschrieben
    class MyEventHandler : public Eventhandler {
       void handle (Event@EinEigenesEvent const & event)
       {
          // Behandlung
       }
    
       void handle (Event@EinAnderesEvent const & event)
       {
          // Behandlung
       }
    };
    
    // später noch eine Erweiterung
    class NocheinEventHandler : public MyEventhandler {
       void handle (Event@ZusätzlichesEvent const & event)
       {
          // Behandlung
       }
    };
    


  • ness schrieb:

    @otze:
    Versteh ich nicht.

    template<class T,U>
    struct inherits
    {
    private:
        struct big{char[2];};
        typedef char small;
        T create_t();
        small test(...);
        big test(const U&);
    public:
        enum{inherits=sizeof(test(create_t()))==sizeof(big)};
    };
    

    Da wäre noch das Problem, dass hier auf implizite Konvertierung getestet wird, und publicvererbung nunmal die geläufigste ist.
    Wie sieht das 2. aus?

    erstmal zur ersten methode:da sie so nur auf implizite konvertierung testet, wird sie etwas anders benutzt:

    template<class T,U>
    struct inherits
    {
    private:
        struct big{char[2];};
        typedef char small;
        T* create_t();
        small test(...);
        big test(const U*);
    public:
        enum{value=sizeof(test(create_t()))==sizeof(big)};
    };
    

    es werden nur zeiger verwendet, wodurch dann der user nicht mehr durch irgendwelche impliziten konvertierungen ins handwerk fuschen kann.

    benutzt man das aber bei

    class Foo:Bar{};
    
    //...
    if(inherits<Foo,Bar>::value){
    }
    

    dann passiert folgendes: der compiler sieht: foo ist von Bar abgeleitet,
    zu diesem zeitpunkt checkt er aber noch nicht, ob Foo private geerbt hat, oder nicht.

    nun sieht er die beiden funktionen:

    small test(...);
    big test(const U*);

    ok: die erste funktion passt immer, hat aber die niedrigste priorität, weshalb er noch die nächste funktion checkt. da er wie bereits gesagt nochnicht auf private vererbung getested hat, passt nun die zweite funktion perfekt. die wählt er also auch.

    erst jetzt merkt der compiler den schund mit der private vererbung und wirft zwangsweise einen error. (Dieses verhalten ist standardkonform)

    die andere methode ist unweit komplizierter, und ich geb zu,dass dies über meinem Horizont liegt:

    //B=Base D=Derived
    template <typename B, typename D>
    struct bd_helper
    {
        template <typename T>
        static type_traits::yes_type check_sig(D const volatile *, T);
        static type_traits::no_type  check_sig(B const volatile *, int);
    };
    
    template<typename B, typename D>
    struct is_base_and_derived_impl2
    {
        struct Host
        {
            operator B const volatile *() const;
            operator D const volatile *();
        };
    
        static const bool value =
            sizeof(bd_helper<B,D>::check_sig(Host(), 0)) == sizeof(type_traits::yes_type));
    };
    

    diese version kriegt alles: private vererbung und sogar fälle in der die abgeleitete Klasse mehrmals von Base abgeleitet ist!

    //edit in den boost traits in der is_base_and_derived.hpp ist ne ausführliche erklärung.

    @Helium genau sowas meinte ich 🙂



  • Die 2. is ja goil. Ich meine, eigentlich ist das ganz logisch, aber sich sowas auszudenken??? Krank, einfach nur krank.

    erst jetzt merkt der compiler den schund mit der private vererbung und wirft zwangsweise einen error. (Dieses verhalten ist standardkonform)
    Was ist das denn für eine komische Regelung? Gibts da irgend ne logische Erklärung für?



  • frag mich nicht. war auch baff, als man mir hier im forum auf die Frage diese antwort gegeben hat.

    btw: wie funktioniert denn nun genau die 2. möglichkeit? was hat das volatile damit zu tun?



  • Was ist für dich die 2. Möglichkeit? Wozu da volatile steht hab ich nicht gecheckt, hast dus mal ohne Probiert?



  • also, wenn es ne bedeutung hat, dann wohl nur in ganz speziellen fällen.

    ich habs so verändert:

    template <typename B, typename D>
    struct bd_helper
    {
        template <typename T>
        static int check_sig(D*,T);
        static char  check_sig(B*,int);
    };
    
    template<typename B, typename D>
    struct is_derived
    {
        struct Host
        {
            operator B*()const;
            operator D*();
        };
    
        static const bool value =sizeof(bd_helper<B,D>::check_sig(Host(),0)) == sizeof(int);
    };
    

    das war die tesklasse:

    class Bar{};
    class A:private Bar{};
    class B:private Bar{};
    class Foo:A,B{};
    

    und das die tests:

    std::cout<<is_derived<Bar,Foo>::value<<"\n";//da ist alles drin
    std::cout<<is_derived<A,B>::value<<"\n";//einfach 2 klassen genommen :D
    std::cout<<is_derived<Bar,A>::value<<"\n";//public vererbung
    

    //edit vielleicht weis es ja wer anders, aber ich komm da nich weiter, ich versteh zwar halbwegs wie das bei public vererbung/keine vererbung abläuft, aber wie er nun an dem test vorbeikommt, dass da ne private vererbung mit im spiel ist, weis ich net

    //edit kommando zurück, dachte eigentlich ich hätts, dann hab ich grad ebend gemerkt, dass es doch ne ganze ecke härter is als gedacht 😕

    //edit wieso ist das bitte die funktion, die anzeigt, dass das hier der derived type ist?

    template <typename T>
        static int check_sig(D*,T);
    

    dann dürfte Host doch nur nach D* konvertieren, da ja nur Up-Casts implizit geschiehen, wenn Host nach B* konvertieren würd, wär das dochn Down cast...ach is das vertrackt 😕



  • Ich glaube, der größte Trick ist die Tatsache, dass keine upcast gebraucht werden.

    Public:
    Host -> Host -> D* -> D*= Fn1
    Host -> Host -> D* -> B* = Fn2
    Host -> const Host -> B* -> B*= Fn2
    Hier ist (warum auch immer) Nr 1 am besten. Außerdem ist der 2. Parameter egal.

    Nix:
    Host -> Host -> D* -> D* = Fn1
    Host -> const Host -> B* -> B*= Fn2
    Hier ist der Aufruf vom 2. Parameter abh., da wird nat. int statt T gewählt. Ohne den 2. Parameter wäre der Aufruf mehrdeutig.

    Mehrdeutig:
    Host -> Host -> D* -> D*= Fn1
    Host -> const Host -> B* -> B*= Fn2
    Kompiler denkt:
    Host -> Host -> D* -> Mitte1*/Mitte2* -> B* = Fn2
    Nicht vom 2. Parameter abh., es wird gleich Host -> D* gewählt

    Private:
    Host -> Host -> D* -> D*= Fn1
    Host -> const Host -> B*-> B* = Fn2
    Kompiler denkt:
    Host -> -> Host -> D* -> B* = Fn2
    Auch nicht vom 2. Parameter abh. Sieht ja genauso aus wie public, daher gleich nr. 1.

    Sieht so aus als ob ich das soweit kapiert hab. Nur kann ich nicht die Absätze im Standard zitieren wo steht, dass gerade diese casts am besten sind.
    Bei den private/ambigous vererbungen ist der Trick glaube ich folgender:
    Zunächst sieht es so aus, als ob die unmögliche Konvertierung ("Kompiler denkt") möglich ist. Es ergeben sich also mehrere Konvertierungsmöglichkeiten. Dadurch, dass diese unmöglichen Konvertierungen da sind, wird die mögliche Konvertierung verbessert und gewählt. Es kommt also nicht zu einer falschen konvertierung.
    Wie gesagt, ich kenn die Regeln dazu nicht, aber das klingt logisch für mich.
    /edit: komplette castwege (mit ICs) hinzugefügt

    Nehmen wir mal
    Public:
    1.: Host -> Host -> D* -> D*= Fn1
    2.: Host -> Host -> D* -> B* = Fn2
    3.: Host -> const Host -> B* -> B*= Fn2
    Aus irgend einem Grund ist 2. besser als 3. In boost wird auf proper subset gepocht, mir ist aber nicht klar was das ist und ich glaube das hat jetzt nix damit zu tun. Ich nehm es erst mal so hin, wenn das jemand erklären könnte? Und dann qualifiziert sich 1. vor 2., weil es nur perfect match -> UDC -> perfect match is und 3. am ende ne (pointer) conversion hat. Bei private ists genauso. Nicht vererbt ist klar (so klar wie es eben sein kann :D), bleibt noch mehrdeutig:

    Mehrdeutig:
    1.: Host -> Host -> D* -> D*= Fn1
    2.: Host -> const Host -> B* -> B*= Fn2
    Kompiler denkt:
    3.: Host -> Host -> D* -> Mitte1*/Mitte2* -> B* = Fn2
    Erst qualifiziert sich 3. vor 2. und dann ist 1. kürzer als 3. Private ambigous ist klar, ist das selbe wie public ambigous.

    Die Frage ist also:
    Warum qualifiziert sich (in diesem Kontext) Host -> Host -> D* -> B* = Fn2 bzw. Host -> Host -> D* -> Mitte1*/Mitte2* -> B* = Fn2 besser als Host -> const Host -> B* -> B*= Fn2?

    Zum 2. Fall schreibt boost:
    According to 13.3.3.1/4, in context of user-defined conversion only the
    standard conversion sequence is considered when selecting the best viable
    function, so it only considers up to the user-defined conversion. For the
    first function this means choosing between C -> C const and C -> C, and it
    chooses the latter, because it's a proper subset (13.3.3.2/3/2) of the
    former.
    Ist mir nicht wirklich klar...
    /edit: @otze: Ich glaube das const spielt nur bei der Frage oben ne Rolle.


Anmelden zum Antworten