Non-Static-Methode als DefParam der selben Klasse nicht möglich?



  • class A
    {
        public:
            unsigned long int func ()
            {
                return(0);
            }
    
            void func2 (unsigned long int param = func())
            {
                cout << "Compilerfehler, verdammt warum?" << endl;
            }
    };
    

    Was kann ich machen? Warum kann der nicht this->func() einsetzen?

    MSDN-Fehlermeldung:

    'Klasse::Funktion' : Unzulässiger Aufruf einer nichtstatischen Member-Funktion

    Die angegebene nichtstatische Member-Funktion wurde in einer statischen (static) Member-Funktion aufgerufen.

    Was mich etwas wundert, weil *keine* der beiden Funktionen static ist.

    MfG SideWinder



  • hm, weiß nicht ob und wie das ginge, aber du könntest es stattdessen so machen:

    void func2(int);
    void func2() { func2(func()); }
    


  • Mir klar, aber so will ich das nicht 😉

    Warum geht das so nicht wie ich das gemacht habe? 😞

    MfG SideWinder



  • Weil ein Default Parameter etwas statisches
    sein muss, Konstanten etc halt.

    func() is aber ned statisch, da sich
    ja erst zur Laufzeit ergibt, was das
    Ergebniss ist.



  • Tankian schrieb:

    Weil ein Default Parameter etwas statisches
    sein muss, Konstanten etc halt.

    func() is aber ned statisch, da sich
    ja erst zur Laufzeit ergibt, was das
    Ergebniss ist.

    Das ist nicht der Grund. Wäre func eine freie Funktion oder eine statische Memberfunktion, wäre der Code durchaus korrekt.

    Das:

    class A
    {
        public:
            unsigned long int func ()
            {
                return(0);
            }
    
            void func2 (unsigned long int param = func())
            {
                cout << "Compilerfehler, verdammt warum?" << endl;
            }
    };
    

    ist aber äquivalent zu:

    class A
    {
        public:
            unsigned long int func ()
            {
                return(0);
            }
    
            void func2 (unsigned long int param = this->func())
            {
                cout << "Compilerfehler, verdammt warum?" << endl;
            }
    };
    

    und im Standard steht unter 8.3.6p8:

    The keyword this shall not be used in a default argument of a member function

    Das macht auch sinn, da nach 9.3.2 der this-Pointer nur im *Body* einer nicht statischen Memberfunktion das Objekt für das die Methode aufgerufen wurde repräsentiert. Die Parameterliste gehört nun aber nicht zum Body.



  • Tankian schrieb:

    Weil ein Default Parameter etwas statisches
    sein muss, Konstanten etc halt.

    Default Parameter werden zur Laufzeit ausgewertet, müssen also weder statisch noch konstant sein.

    @HumeSikkins
    Deine Begründung klingt logisch. Trotzdem, macht das eigentlich Sinn? Vor dem Aufruf der Methode muss ja this (respektive das Objekte, das sich dahinter verbirgt) bekannt sein. Und erst beim Aufruf der Methode werden die default Parameter ausgewertet. Also sollte sowas doch theoretisch möglich sein?



  • Hallo,
    kleines Beispiel:

    class Foo
    {
    public:
         Foo(std::string s = getString())
             : s_(s)
         {}
         std::string getString() const {return s_;}
    private:
        std::string s_;
    };
    
    int main()
    {
         Foo f;   // ups! Aufruf von getString und Zugriff auf s_ *bevor* der Ctor
                  // gelaufen ist, sprich *bevor* s_ initialisiert wurde -> Aua!
    }
    

    Hinzukommend ist in C++ die Auswertung von Funktionsparametern nicht definiert. Es ist der Implementation überlassen in welcher Reihenfolge sie Funktionsparamter auswertet. Würde man die Verwendung von this in der Parameterliste einer Funktion zulassen, wäre dies nicht mehr möglich.
    Es würde dabei auch nicht reichen, wenn man nur fordern würde, dass this zuerst ausgewertet werden muss.
    Spätestens hier:

    class Foo
    {
    public:
         void func(int i = gunc(), int j = hunc());
         void gunc();
         void hunc();
    };
    

    hättest du dann wieder ein Problem.

    Es gibt sicher noch andere Gründe die mir jetzt spontan aber nicht einfallen 🙂



  • Dein Bsp. ist klar. Nur sollte sowas nicht in der Verantwortung des Programmierers liegen? Folgendes Bsp. lässt sich "legal" compilieren und verursacht die gleichen Probleme.

    class Foo
    {
    public:
         Foo(std::string s)
             : s1_(getString())
             , s2_(s)
         {}
         std::string getString() const {return s2_;}
    private:
        std::string s1_, s2_;
    };
    
    int main()
    {
         Foo f("mein foo");
    }
    

    HumeSikkins schrieb:

    Es ist der Implementation überlassen in welcher Reihenfolge sie Funktionsparamter auswertet.

    Ist mir bekannt.

    HumeSikkins schrieb:

    Würde man die Verwendung von this in der Parameterliste einer Funktion zulassen, wäre dies nicht mehr möglich.

    Darüber muss ich nochmal näher nachdenken, da ich momentan nicht ganz verstehe was du damit meinst.



  • groovemaster2002 schrieb:

    Dein Bsp. ist klar. Nur sollte sowas nicht in der Verantwortung des Programmierers liegen?

    Wobei in meinem Beispiel dann aber die Verantwortung nicht nur beim Klassenimplementierer sondern auch beim Client liegt. Ist ja schon ärgerlich, wenn der Client immer einen Parameter angibt und alles ist toll. Eines Tages macht er aber vom Def-Parameter gebrauch und bumm -> undefiniertes Verhalten.

    Um meinen zweiten Punkt kommst du aber nicht drum rum. Mal abgesehen davon, dass die Funktionen gunc und hunc in dem Beispiel int liefern müssten: stell dir vor gunc und hunc ändern beide den Zustand vom Objekt und liefern dann einen Teil des Zustands zurück.
    Solange die Auswertungsreihenfolge nicht fest definiert ist, könnte man in diesem Fall nie sagen, welche Werte die Def-Params erhalten. Das wäre dann von Compiler zu Compiler unterschiedlich.

    Lustig wird's dann auch mit virtuellen Funktionen. Soll die aufzurufende Funktion über den statischen oder den dynamischen Typ bestimmt werden. Wenn's der statische Typ sein soll, vorsicht mit pure virtual Funktionen. Soll es aber der dynamische Typ sein, kannst du den Aufruf einer Funktion auf einmal unmöglich machen, indem du eine neue Vererbungsbeziehung einführst (-> Mehrdeutigkeit dank MI).

    Vielleicht hilft dir auch dieser Thread



  • Tja hat der User Pech gehabt, entweder ich überlade die Methode oder er kann so gut wie jedesmal seinen zweiten Parameter brav selbst angeben 🙂

    MfG SideWinder



  • BTW: Das hier ist doch dann genauso undefiniert:

    class klasse
    {
        public:
            int func1 () { return(m_int); }
            int func2 () { return(++m_int); }
            int func3 (int a, int b) { return(a+b); }
    };
    
    klasse obj;
    obj.setInt(5);
    obj.func3(obj.func1(),obj.func2()); // Fall 1: func3(5,6) Fall 2: func3(6,6)
    

    Warum ist das gültig, der Def-Param hingegen nicht?

    MfG SideWinder



  • SideWinder schrieb:

    BTW: Das hier ist doch dann genauso undefiniert:

    Das ist nicht undefiniert sondern unspecified. Das ist ein großer Unterschied!

    Im Gegensatz zu einem Def-Parameter sieht man hier aber das Problem (man muss es sogar explizit hinschreiben).



  • HumeSikkins schrieb:

    Wobei in meinem Beispiel dann aber die Verantwortung nicht nur beim Klassenimplementierer sondern auch beim Client liegt.

    Wobei das imo nie der Fall sein darf. Die Verantwortung muss immer beim Implementierer liegen. Egal ob ein Client def-Params nutzt oder nicht, darf das nicht zu einem undefinierten Verhalten führen.

    HumeSikkins schrieb:

    Um meinen zweiten Punkt kommst du aber nicht drum rum. Mal abgesehen davon, dass die Funktionen gunc und hunc in dem Beispiel int liefern müssten: stell dir vor gunc und hunc ändern beide den Zustand vom Objekt und liefern dann einen Teil des Zustands zurück.

    Jep, jetzt ist mir klar was du meinst. Und du hast Recht, da komm ich tatsächlich nicht drum rum. 🙂


Anmelden zum Antworten