Vererbungsproblem



  • Ok, funktioniert jetzt wunderbar. Auch das hinzufügen von z.B. TextLabels funktioniert und führt keinen Absturz herbei.

    Nochmal ne Frage zu der Nicht-Verwendung von NULL. Wenn ich einen Zeiger

    SubMenu *m_pSubMenu;
    

    habe, brauche ich den wahrscheinlich auch nicht bei der Initialisierung der Klasse auf NULL setzen, oder?

    m_pSubMenu = NULL;
    

    @Nick Unbekannt
    Nene ist kein VCL, ich schreibe eine eigene Library auf Basis von OpenGL.

    @this->that
    Ein leerer Funktionsrumpf wäre noch eine Idee, allerdings gefällt mir das dynamic cast dann doch besser.



  • Student83 schrieb:

    Nochmal ne Frage zu der Nicht-Verwendung von NULL. Wenn ich einen Zeiger

    SubMenu *m_pSubMenu;
    

    habe, brauche ich den wahrscheinlich auch nicht bei der Initialisierung der Klasse auf NULL setzen, oder?

    m_pSubMenu = NULL;
    

    Man nimmt einfach `0':

    SubMenu *m_pSubMenu = 0;
    

    Das macht aber auch niemand, weil es die Initialisierungsliste gibt, die alles effizienter und etwas kürzer macht:

    MenuItem::MenuItem() // Konstruktor halt
      : m_pSubMenu(0), // Doppelpunkt und dann member0(wert0), member1(wert1),..., memberN(wertN) { ... }
        m_bIsChecked(false) {
      // hier ist's dann meistens leer.
    }
    

    Ich könnte mich jetzt noch über deine UN beschweren, über mangelnde Kenntnis vom Geist von C++ und über die daraus entstehenden Designfehler wie den dynamic_cast (hier jetzt, zugegeben, die einfachste Lösung), aber ich lasse es besser darauf beruhen.

    In C++0x gibts für spezielle Fälle eine Alternative zu 0, wenn du beispielsweise die überladene Funktion foo() vor dir hast:

    void foo(int i) { }
    void foo(void *p) { }
    
    foo(0); // wie kann ich foo(void *) aufrufen?
    // bis jetzt:
    foo((void *)0);
    // ab C++0x (oder auch jetzt möglich mit templates):
    foo(nullptr);
    

    Ob man das dann konsequent verwenden soll, ist die andere Frage, aber auf jeden Fall _nicht_ mit Makros wie NULL.



  • Das ist Unsinn. Der Typ 0 != (void*)0 das ist aber genau die Bedeutung die NULL in C++ hat. Auch gibt es keine Notwendigkeit, dass NULL == false sein muss. Die Adresse 0x0 kann auf einem System genauso gültig sein, wie jede andere Adresse. Eine Überprüfung auf NULL ist somit sogar richtiger, als eine Überprüfung auf false. Ganz davon abgesehen, dass bei strikter Prüfung weder void * foo = 0 erlaubt ist, noch *foo als Boolean-Typ interpretiert werden darf.



  • Ich bin nicht der Meinung, dass man die Verwendung von NULL verteufeln sollte. Jedoch kann dies zu Unklarheiten und Fehlern führen. Das Makro ist wie folgt definiert:

    #ifndef NULL 
    #ifdef __cplusplus 
    #define NULL 0 
    #else 
    #define NULL ((void *)0) 
    #endif 
    #endif
    
    //Somit ist in C 
    NULL = ((void *)0)
    //und in C++ 
    NULL = 0
    

    wie vorher erwähnt kommt bald der nullptr dazu. Dieser wird aus Kompatibilitätsgründen nicht NULL ersetzen, sondern ein eigener typ werden. Dann kann man sowas machen:

    #include <iostream>
    using std::cout;
    
    void foo(char *chr){cout << "char\n";}
    void foo(int i){cout << "int\n";}
    
    int main()
    { 
    	foo(nullptr); //Anstelle von: "foo((char *)0);"
    	foo(NULL);
    
    	system("pause");
    	return 0; 
    }
    

    Spätestens Jetzt wurden mehr Unklarheiten geschaffen 😛

    Hier noch ein schöner Link zur Problematik:
    http://www.devx.com/cplus/10MinuteSolution/35167/1954



  • Nick Unbekannt schrieb:

    Die Adresse 0x0 kann auf einem System genauso gültig sein, wie jede andere Adresse.

    Nein, kann sie nicht. C++ garantiert, dass das Integer-Literal 0 (und damit auch die hexadezimale Variante) in einen Nullzeiger konvertiert werden kann.

    4.10/1 Pointer conversions schrieb:

    A null pointer constant is an integral constant expression (5.19) rvalue of integer type that evaluates to zero. A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type and is distinguishable from every other value of pointer to object or pointer to function type.

    Nick Unbekannt schrieb:

    Ganz davon abgesehen, dass bei strikter Prüfung weder void * foo = 0 erlaubt ist, noch *foo als Boolean-Typ interpretiert werden darf.

    Wie gesagt ist

    void* ptr = 0;
    

    sehr wohl erlaubt, Gleiches gilt für die Interpretation als bool . Sonst würde

    if (ptr)
    

    nicht funktionieren. Quelle:

    4.12/1 Boolean conversions schrieb:

    An rvalue of arithmetic, enumeration, pointer, or pointer to member type can be converted to an rvalue of type bool. A zero value, null pointer value, or null member pointer value is converted to false; any other value is converted to true.



  • Zur Verwendung von NULL :

    Ich persönlich benutze momentan

    // Teilweiser Workaround für sicheren Nullzeiger
    // Die globale Variable nullptr kann in vielen Fällen als Nullzeiger-Literal verwendet werden.
    // Einschränkungen gibt es bei Memberfunktionszeigern.
    const class nullptr_t
    {
    	public:
    		// Konvertierbar in Zeigertypen
    		template <typename T>
    		operator T* () const
    		{
    			return 0;
    		}
    
    		// Konvertierbar in Zeiger auf Member
            template <class C, typename T> 
            operator T C::* () const 
            { 
                return 0; 
            } 
    
    	private:	
    		// Nicht adressierbar
    		void* operator& ();
    
    } nullptr = {};
    

    oder in einer Bibliothek noch NULL , um nicht zu viele Leute zu verwirren. Mir ist NULL immer noch lieber als 0 , weil unmittelbar klar ist, dass es sich um Zeiger handelt. Aber man muss sich dabei bewusst sein, dass man selbst für diese Sicherheit zu sorgen hat (anders bei nullptr , entweder selbstgebaut oder aus C++0x).


  • Mod

    Nexus schrieb:

    Nick Unbekannt schrieb:

    Die Adresse 0x0 kann auf einem System genauso gültig sein, wie jede andere Adresse.

    Nein, kann sie nicht. C++ garantiert, dass das Integer-Literal 0 (und damit auch die hexadezimale Variante) in einen Nullzeiger konvertiert werden kann.

    4.10/1 Pointer conversions schrieb:

    A null pointer constant is an integral constant expression (5.19) rvalue of integer type that evaluates to zero. A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type and is distinguishable from every other value of pointer to object or pointer to function type.

    Das hat allerdings nichts mit Adressen zu tun (und insofern hat Nick unbekannt recht). Schließlich kann ein Zeiger ohnehin nicht (direkt) mit einer bestimmten Adresse initialisiert werden.



  • Vielen Dank für den Hinweis.

    Du hast Recht, das Mapping zwischen integralen Typen und tatsächlichen Adressen ist implementierungsabhängig (soweit ich weiss, müsste eine Adresse theoretisch nicht einmal als Ganzzahl dargestellt sein). Wenn ich das richtig verstehe, kann man also gar keine portable Aussage über Adressen treffen, sondern nur über die intergrale Darstellung von ihnen (durch reinterpret_cast ).



  • @Schüler93
    Mit UN meinst du wahrscheinlich die Ungarische Notation. Was ist denn an meinen Bezeichnern "verkehrt"?

    Außerdem ist OpenGL ja in C geschrieben, d.h. reines C++ ist also eh nicht möglich.



  • Student83 schrieb:

    @Schüler93
    Mit UN meinst du wahrscheinlich die Ungarische Notation. Was ist denn an meinen Bezeichnern "verkehrt"?

    Ich hab vor einiger Zeit etwas Ausführlicheres dazu geschrieben.

    Student83 schrieb:

    Außerdem ist OpenGL ja in C geschrieben, d.h. reines C++ ist also eh nicht möglich.

    Du kannst trotzdem versuchen, für deine Bibliothek so sauberes C++ wie möglich zu verwenden. SFML basiert beispielsweise auch auf OpenGL, aber ich würde SFML als eine der Bibliotheken mit modernstem/elegantestem C++-Design bezeichnen.



  • int a = 0; 
    int b = 0;
    if(a++ || b--) 
       b = a;
    
    std::cout << a << "\n";
    std::cout << b << "\n";
    
    if(a++ && b--)
       b = 15;
    
    std::cout << a << "\n";
    std::cout << b << "\n";
    

    Ist das Ergebnis definiert oder undefiniert?
    Ich habe: 1, -1, 2, 15


Anmelden zum Antworten