Funktion <=> Instanz



  • Warum ist

    Foo foo;
    

    nicht equivalent zu

    Foo foo();
    

    ,
    wenn Foo folgendermassen definiert ist:

    class Foo
        {
        private:
          int i;
        public:
          Foo(int i=0) : i(i)
          {}
    
          int get() const
          {
            return i;
          }
        };
    

    Durch den default-Parameter im Ctor muesst doch auch bei

    Foo foo();
    

    eine Instanz, mit dem i-Wert 0 angelegt werden.
    Genauso, wie bei

    Foo foo();
    

    und

    Foo foo(0);
    

    .
    Diese drei muessten doch absolut gleich sein.

    Der Compiler meldet aber, wenn folgendes compiliert wird

    #include <iostream>
        using namespace std;
    
        class Foo
        {
        private:
          int i;
        public:
          Foo(int i=0) : i(i)
          {}
    
          int get() const
          {
            return i;
          }
        };
    
        int main()
        {
          Foo f();
          cout<<f.get()<<'\n';  //Krach
    	  return 0;
        }
    
    error C2228: Der linke Teil von '.get' muss eine Klasse/Struktur/Union sein
    


  • weil

    Foo foo();
    

    eine Funktions Deklaration ist und keine Objekt definition.

    🙄



  • mit Foo f(); deklarierst du eine Funktion, lass die Klammern weg.



  • Warum ist es keine Objekt Definition?
    Die Klammern koennten ja auch fuer den Ctor stehen.



  • Das ist so definiert damit es keine Verwechselungsgefahr gibt.



  • int funktion();

    habe ich jetzt eine Funktion deklariert oder eine Variable definiert?

    Niemand weiss es - deshalb haben schlaue Leute sich gedacht: bestimmen wir doch einfach was das ist. Es sieht wie eine Funktion aus, also lassen wir es eine Funktion sein.

    Ein Objekt kann man ja auch ohne Klammern definieren - eine Funktion nicht. Daher war die Wahl auch nicht schwer 😉



  • Und woher weiss ich jetzt, ob ich eine Funktion deklariere, bzw. ein Object definiere. Wo ist das festgelegt?



  • Foo foo();
    

    das kann der compiler nich auflösen, weil damit sowohl ne funktion foo mit returnwert Foo ohne parameter deklariert werden könnte, als auch ein Objekt foo vom typ Foo ohne parameter im ctor



  • Raptor schrieb:

    Und woher weiss ich jetzt, ob ich eine Funktion deklariere, bzw. ein Object definiere. Wo ist das festgelegt?

    Im Standard.

    Es ist ganz simpel:
    wenn du
    Foo foo(); schreibst, ist es eine Funktion
    Foo foo; ist eine Variable

    Foo foo(int); ist eine Funktion
    und
    Foo foo(3); ist eine Variable

    im Prinzip kann man sagen: alles was eine funktion sein koennte, ist eine Funktion.

    deshalb auch folgendes:

    class A
    {
    
    };
    
    class B
    {
    public:
      B(A a) {}
    };
    
    int main()
    {
      B b(A()); //funktion
    }
    

    B b(A());
    ist eine Funktion, die ein B liefert und einen Zeiger auf eine Funktion, die ein A liefert und keine Parameter hat, erwartet



  • shade, bei mir kompiliert der das fehlerlos^^
    //edit doch hast wohl recht Oo



  • otze schrieb:

    shade, bei mir kompiliert der das fehlerlos^^
    //edit doch hast wohl recht Oo

    um es klarer zu stellen:

    folgendes kompiliert nicht:

    class A
    {
    
    };
    
    class B
    {
    public:
      B(A a) {}
      void foo() {}
    };
    
    int main()
    {
      B b(A()); //funktion
      b.foo();
    }
    

    Denn b ist, wie schon gesagt, eine Funktion.

    Mein erster code kompiliert natuerlich auch - die Deklaration einer Funktion ist ja vollkommen legal (nur eben nicht das, was wir erwarten)



  • [OT]Oh, Shade, wo du grad mal da bist noch eine Frage.
    Hab mir mal den Code zu deinem TicTacToe-Game angeschaut.
    Eines verstehe ich nicht.

    //Methode mit 0 Parametern
    template<typename Class>
    class MenuEntryMethod : public MenuEntry
    {
    public:
      typedef void (Class::*Method)();
    private:
      Class* p;
      Method method;
      std::string name;
    
    protected:
      void do_action()
      {
        (p->*method)();
      }
      std::string do_getName() const
      {
        return name;
      }
    
    public:
      MenuEntryMethod(Class* p, Method method, std::string const& name)
      : p(p), method(method), name(name)
      {}
    };
    

    In der Klasse machst
    MenuEntryMethod so etwas:

    typedef void (Class::*Method)();
    

    Du gibst also dem Typen void den Aliasnamen (Class::*Method)() ???
    Und woher kommt der Typ

    Method method;
    

    dann auf einmal?
    Und was machst du hier dann genau:

    (p->*method)();
    

    ?
    [/OT]



  • Raptor schrieb:

    Du gibst also dem Typen void den Aliasnamen (Class::*Method)() ???
    Und woher kommt der Typ

    nein, nicht void

    Ich lege einen Typen Method an, der ein Zeiger auf eine Methode ist.
    Der Typ ist:
    void (Class::)();
    das ist ein Zeiger auf eine Methode.
    ein zeiger auf eine funktion sieht zB so aus:
    void (
    )();
    und dann fuege ich lediglich den namen ein ->
    void (*foo)();

    etwas ungewoehnlich diese syntax, ich weiss. C++ ist syntaktisch gesehen nicht wirklich schoen 😞

    schau dir mal www.function-pointer.org an. Dann sollte es dir klar werden. Wenn nicht - frag nochmal

    Und was machst du hier dann genau:

    (p->*method)();
    

    Ich rufe die Methode mit einem Objekt auf.
    Jede Methode braucht ja ein Objet auf das sie angewandt wird.

    und mit dieser Zeile mache ich nichts anderes als die Methode ueber einen Zeiger mit dem Objekt p aufzurufen.



  • Und was soll der * da?



  • Der * gehört zum binären Operator ->* (nicht lachen, den gibt's wirklich). Links steht ein Zeiger auf ein Objekt, rechts ein Zeiger auf einen Member und der Operator macht in diesem Fall eine aufrufbare Funktion daraus.



  • tag schrieb:

    Der * gehört zum binären Operator ->* (nicht lachen, den gibt's wirklich). Links steht ein Zeiger auf ein Objekt, rechts ein Zeiger auf einen Member und der Operator macht in diesem Fall eine aufrufbare Funktion daraus.

    Ich dachte immer das wäre ne Combo aus -> und * 😕 . Mit * würde man den Pointer dereferezieren und dann die Funktion dann ganz gewöhnlich mit -> aufrufen.



  • ne, das merkt man zb auch daran, dass der ->* operator nicht überladbar ist



  • otze schrieb:

    ne, das merkt man zb auch daran, dass der ->* operator nicht überladbar ist

    IMHO ist er aber überladbar!



  • nö man kann ihn net überladen, genauso wie der .* operator




Anmelden zum Antworten