How are POD structs associated with member functions?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • JohnQ

    How are POD structs associated with member functions?

    The implementation of classes with virtual functions is conceptually easy to
    understand: they use vtables. Which begs the question about POD structs: how
    are they associated with their member functions in common implementations ?
    And where is the 'this' ptr tucked away at for POD structs with member
    functions?

    John

  • Victor Bazarov

    #2
    Re: How are POD structs associated with member functions?

    JohnQ wrote:
    The implementation of classes with virtual functions is conceptually
    easy to understand: they use vtables. Which begs the question about
    POD structs: how are they associated with their member functions in
    common implementations ? And where is the 'this' ptr tucked away at
    for POD structs with member functions?
    Yes, the 'this' pointer is usually passed into the function as the
    hidden "zeroth" argument.

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask


    Comment

    • JohnQ

      #3
      Re: How are POD structs associated with member functions?


      "Victor Bazarov" <v.Abazarov@com Acast.netwrote in message
      news:f5h3if$mpa $1@news.datemas .de...
      JohnQ wrote:
      >The implementation of classes with virtual functions is conceptually
      >easy to understand: they use vtables. Which begs the question about
      >POD structs: how are they associated with their member functions in
      >common implementations ? And where is the 'this' ptr tucked away at
      >for POD structs with member functions?
      >
      Yes, the 'this' pointer is usually passed into the function as the
      hidden "zeroth" argument.
      The question is how the functions are staticly associated with the struct.
      So there's this POD-struct in RAM, for example, and a member function get's
      called. The POD-struct is the size of the data members so there's nothing in
      it pointing to the functions apparently. How can the dot or -operators
      access the member functions? Some kind of special compiler-only overloading
      of the member access operators that can distinguish between data member and
      member function access?

      John

      Comment

      • Gavin Deane

        #4
        Re: How are POD structs associated with member functions?

        On 23 Jun, 11:19, "JohnQ" <johnqREMOVETHI Sprogram...@yah oo.comwrote:
        "Victor Bazarov" <v.Abaza...@com Acast.netwrote in message
        >
        news:f5h3if$mpa $1@news.datemas .de...
        >
        JohnQ wrote:
        The implementation of classes with virtual functions is conceptually
        easy to understand: they use vtables. Which begs the question about
        POD structs: how are they associated with their member functions in
        common implementations ? And where is the 'this' ptr tucked away at
        for POD structs with member functions?
        >
        Yes, the 'this' pointer is usually passed into the function as the
        hidden "zeroth" argument.
        >
        The question is how the functions are staticly associated with the struct.
        So there's this POD-struct in RAM, for example, and a member function get's
        called. The POD-struct is the size of the data members so there's nothing in
        it pointing to the functions apparently.
        Why would there need to be?

        Obviously *how* it actually works is an implementation detail. All
        that matters is that the required behaviour is exhibited. But I would
        think something along the lines of this:

        You write

        struct foo
        {
        void func() { i = 42; }

        int i;
        };

        int main()
        {
        foo a_foo;
        a_foo.func();

        foo another_foo;
        another_foo.fun c();

        foo a_third_foo;
        a_third_foo.i = 42;
        }

        The compiler treats it along the lines of

        struct foo
        {
        int i;
        };
        void foo_func(foo* this) { this->i = 42; }

        int main()
        {
        foo a_foo;
        foo_func(&a_foo );

        foo another_foo;
        foo_func(&anoth er_foo);

        foo a_third_foo;
        a_third_foo.i = 42;
        }

        I'm not suggesting the compiler actually rewrites your code to look
        like that - just illustrating what's probably going on.
        How can the dot or -operators
        access the member functions? Some kind of special compiler-only overloading
        of the member access operators that can distinguish between data member and
        member function access?
        Given my struct foo above, the compiler knows which members are
        functions (func) and which are data members (i). When I do

        a_third_foo.i = 42;

        it knows which foo object I want to work with (a_third_foo), it knows
        where that object is in memory (wherever it put it) and it knows
        where, within that memory, the int i is that I want to set to 42.

        And when I do

        another_foo.fun c();

        it knows I want to call a function (func), it knows where the code for
        that function is (wherever it put it) and it knows which object to
        pass the address of as the hidden "this" parameter (another_foo).

        Gavin Deane

        Comment

        • John Harrison

          #5
          Re: How are POD structs associated with member functions?

          JohnQ wrote:
          >
          "Victor Bazarov" <v.Abazarov@com Acast.netwrote in message
          news:f5h3if$mpa $1@news.datemas .de...
          >JohnQ wrote:
          >>The implementation of classes with virtual functions is conceptually
          >>easy to understand: they use vtables. Which begs the question about
          >>POD structs: how are they associated with their member functions in
          >>common implementations ? And where is the 'this' ptr tucked away at
          >>for POD structs with member functions?
          >>
          >Yes, the 'this' pointer is usually passed into the function as the
          >hidden "zeroth" argument.
          >
          The question is how the functions are staticly associated with the
          struct.
          In the compiled code they aren't.

          So there's this POD-struct in RAM, for example, and a member
          function get's called. The POD-struct is the size of the data members so
          there's nothing in it pointing to the functions apparently. How can the
          dot or -operators access the member functions?
          The compiler works it out.

          Some kind of special
          compiler-only overloading of the member access operators that can
          distinguish between data member and member function access?
          If it helps to think of it like that then yes.
          >
          John
          Consider two programs

          // first program
          struct X
          {
          int get();
          int d;
          };

          int X::get() { return d; }

          // second program
          struct X
          {
          int d;
          };

          int get(X* x) { return x->d; }

          Once compiled these two programs are essentially the same. In some
          region of memory there will be a function 'called' get (of course the
          name has actually disappeared by this point) which takes one argument.
          Inside that function the argument will be assumed to be pointing at an X
          object. Whether that function was originally a member function or a free
          standing function is irrelevant at this point.

          john

          Comment

          • JohnQ

            #6
            Re: How are POD structs associated with member functions?


            "Gavin Deane" <deane_gavin@ho tmail.comwrote in message
            news:1182596028 .651377.12650@k 79g2000hse.goog legroups.com...
            On 23 Jun, 11:19, "JohnQ" <johnqREMOVETHI Sprogram...@yah oo.comwrote:
            >"Victor Bazarov" <v.Abaza...@com Acast.netwrote in message
            >>
            >news:f5h3if$mp a$1@news.datema s.de...
            >>
            JohnQ wrote:
            >The implementation of classes with virtual functions is conceptually
            >easy to understand: they use vtables. Which begs the question about
            >POD structs: how are they associated with their member functions in
            >common implementations ? And where is the 'this' ptr tucked away at
            >for POD structs with member functions?
            >>
            Yes, the 'this' pointer is usually passed into the function as the
            hidden "zeroth" argument.
            >>
            >The question is how the functions are staticly associated with the
            >struct.
            >So there's this POD-struct in RAM, for example, and a member function
            >get's
            >called. The POD-struct is the size of the data members so there's nothing
            >in
            >it pointing to the functions apparently.
            >
            Why would there need to be?
            >
            Obviously *how* it actually works is an implementation detail. All
            that matters is that the required behaviour is exhibited. But I would
            think something along the lines of this:
            >
            You write
            >
            struct foo
            {
            void func() { i = 42; }
            >
            int i;
            };
            >
            int main()
            {
            foo a_foo;
            a_foo.func();
            >
            foo another_foo;
            another_foo.fun c();
            >
            foo a_third_foo;
            a_third_foo.i = 42;
            }
            >
            The compiler treats it along the lines of
            >
            struct foo
            {
            int i;
            };
            void foo_func(foo* this) { this->i = 42; }
            >
            int main()
            {
            foo a_foo;
            foo_func(&a_foo );
            >
            foo another_foo;
            foo_func(&anoth er_foo);
            >
            foo a_third_foo;
            a_third_foo.i = 42;
            }
            >
            I'm not suggesting the compiler actually rewrites your code to look
            like that - just illustrating what's probably going on.
            >
            >How can the dot or -operators
            >access the member functions? Some kind of special compiler-only
            >overloading
            >of the member access operators that can distinguish between data member
            >and
            >member function access?
            >
            Given my struct foo above, the compiler knows which members are
            functions (func) and which are data members (i). When I do
            >
            a_third_foo.i = 42;
            >
            it knows which foo object I want to work with (a_third_foo), it knows
            where that object is in memory (wherever it put it) and it knows
            where, within that memory, the int i is that I want to set to 42.
            >
            And when I do
            >
            another_foo.fun c();
            >
            it knows I want to call a function (func), it knows where the code for
            that function is (wherever it put it) and it knows which object to
            pass the address of as the hidden "this" parameter (another_foo).
            OK. That's a good explanation. Except, I can't see it working for objects
            allocated on the free store.

            John

            Comment

            • John Harrison

              #7
              Re: How are POD structs associated with member functions?

              >
              OK. That's a good explanation. Except, I can't see it working for
              objects allocated on the free store.
              >
              John
              Why not? Gavin's explaination is of course how every compiler does do
              this. Whether an object is allocated on the free store or not is
              irrelevent. Every object has an address, and that is all that is
              required for this too work.

              Clearly you're not understnding something here but I have no idea what.
              It's pretty simple, maybe you're just thinking too hard.

              john

              Comment

              • Gavin Deane

                #8
                Re: How are POD structs associated with member functions?

                On 23 Jun, 12:12, "JohnQ" <johnqREMOVETHI Sprogram...@yah oo.comwrote:
                "Gavin Deane" <deane_ga...@ho tmail.comwrote in message
                You write
                >
                struct foo
                {
                void func() { i = 42; }
                >
                int i;
                };
                >
                int main()
                {
                foo a_foo;
                a_foo.func();
                >
                foo another_foo;
                another_foo.fun c();
                >
                foo a_third_foo;
                a_third_foo.i = 42;
                }
                >
                The compiler treats it along the lines of
                >
                struct foo
                {
                int i;
                };
                void foo_func(foo* this) { this->i = 42; }
                >
                int main()
                {
                foo a_foo;
                foo_func(&a_foo );
                >
                foo another_foo;
                foo_func(&anoth er_foo);
                >
                foo a_third_foo;
                a_third_foo.i = 42;
                }
                >
                I'm not suggesting the compiler actually rewrites your code to look
                like that - just illustrating what's probably going on.
                >
                How can the dot or -operators
                access the member functions? Some kind of special compiler-only
                overloading
                of the member access operators that can distinguish between data member
                and
                member function access?
                >
                Given my struct foo above, the compiler knows which members are
                functions (func) and which are data members (i). When I do
                >
                a_third_foo.i = 42;
                >
                it knows which foo object I want to work with (a_third_foo), it knows
                where that object is in memory (wherever it put it) and it knows
                where, within that memory, the int i is that I want to set to 42.
                >
                And when I do
                >
                another_foo.fun c();
                >
                it knows I want to call a function (func), it knows where the code for
                that function is (wherever it put it) and it knows which object to
                pass the address of as the hidden "this" parameter (another_foo).
                >
                OK. That's a good explanation. Except, I can't see it working for objects
                allocated on the free store.
                There's no difference:

                // struct foo is as above
                int main()
                {
                foo local_foo;
                local_foo.func( ); // Call 1

                foo* dynamic_foo_ptr = new foo;
                dynamic_foo_ptr->func(); // Call 2
                delete dynamic_foo_ptr ;
                }

                For call 1, the compiler knows I want to call a function (func), it
                knows where the code for that function is (wherever it put it) and it
                knows which object to pass the address of as the hidden "this"
                parameter (local_foo).

                For call 2, the compiler knows I want to call a function (func - as
                before), it knows where the code for that function is (wherever it put
                it - exactly the same place as before) and this time it knows it has a
                pointer to the particular foo object for which I want to invoke the
                function func (dynamic_foo_pt r) and so it passes dynamic_foo_ptr as
                the hidden "this" parameter.

                Gavin Deane

                Comment

                • JohnQ

                  #9
                  Re: How are POD structs associated with member functions?


                  "Gavin Deane" <deane_gavin@ho tmail.comwrote in message
                  news:1182599094 .172121.251220@ n2g2000hse.goog legroups.com...
                  On 23 Jun, 12:12, "JohnQ" <johnqREMOVETHI Sprogram...@yah oo.comwrote:
                  >"Gavin Deane" <deane_ga...@ho tmail.comwrote in message
                  You write
                  >>
                  struct foo
                  {
                  void func() { i = 42; }
                  >>
                  int i;
                  };
                  >>
                  int main()
                  {
                  foo a_foo;
                  a_foo.func();
                  >>
                  foo another_foo;
                  another_foo.fun c();
                  >>
                  foo a_third_foo;
                  a_third_foo.i = 42;
                  }
                  >>
                  The compiler treats it along the lines of
                  >>
                  struct foo
                  {
                  int i;
                  };
                  void foo_func(foo* this) { this->i = 42; }
                  >>
                  int main()
                  {
                  foo a_foo;
                  foo_func(&a_foo );
                  >>
                  foo another_foo;
                  foo_func(&anoth er_foo);
                  >>
                  foo a_third_foo;
                  a_third_foo.i = 42;
                  }
                  >>
                  I'm not suggesting the compiler actually rewrites your code to look
                  like that - just illustrating what's probably going on.
                  >>
                  >How can the dot or -operators
                  >access the member functions? Some kind of special compiler-only
                  >overloading
                  >of the member access operators that can distinguish between data
                  >member
                  >and
                  >member function access?
                  >>
                  Given my struct foo above, the compiler knows which members are
                  functions (func) and which are data members (i). When I do
                  >>
                  a_third_foo.i = 42;
                  >>
                  it knows which foo object I want to work with (a_third_foo), it knows
                  where that object is in memory (wherever it put it) and it knows
                  where, within that memory, the int i is that I want to set to 42.
                  >>
                  And when I do
                  >>
                  another_foo.fun c();
                  >>
                  it knows I want to call a function (func), it knows where the code for
                  that function is (wherever it put it) and it knows which object to
                  pass the address of as the hidden "this" parameter (another_foo).
                  >>
                  >OK. That's a good explanation. Except, I can't see it working for objects
                  >allocated on the free store.
                  >
                  There's no difference:
                  >
                  // struct foo is as above
                  int main()
                  {
                  foo local_foo;
                  local_foo.func( ); // Call 1
                  >
                  foo* dynamic_foo_ptr = new foo;
                  dynamic_foo_ptr->func(); // Call 2
                  delete dynamic_foo_ptr ;
                  }
                  >
                  For call 1, the compiler knows I want to call a function (func), it
                  knows where the code for that function is (wherever it put it) and it
                  knows which object to pass the address of as the hidden "this"
                  parameter (local_foo).
                  (I wrote this section after the stuff at the end of the post)

                  The secret ingredient is: how or by what mechanism the compiler knows how to
                  pass the foo to the foo function. OK, it doesn't. You say it does the
                  binding at compile time (yes?). There is no "passing of a foo to a foo func
                  at runtime" as it is "hard coded" in the compiled code (?). So with a free
                  store obj, it does similar and it is enough to know that the pointer to the
                  foo is "hard coded" (like where you said foo_func(&a_foo );) by the compiler
                  and the compiler doesn't care what actual foo is being pointed to. That's it
                  (!) isn't it?
                  >
                  For call 2, the compiler knows I want to call a function (func - as
                  before), it knows where the code for that function is (wherever it put
                  it - exactly the same place as before) and this time it knows it has a
                  pointer to the particular foo object for which I want to invoke the
                  function func (dynamic_foo_pt r) and so it passes dynamic_foo_ptr as
                  the hidden "this" parameter.
                  >
                  I was thinking of something less simplistic than the above example. Your
                  examples show instances where it is easy to comprehend what the compiler is
                  doing. Somewhere, I thought it would be difficult for the compiler to know
                  where class objects of a given class were instantiated (or something like
                  that) so I thought there must be some kind of external mapping of class
                  objects and their functions. Without trying to explain any more what I was
                  thinking, I'm wondering if the examples you show above are how it works ALL
                  the time (for POD-structs with member functions).

                  John

                  Comment

                  • Gavin Deane

                    #10
                    Re: How are POD structs associated with member functions?

                    On 24 Jun, 05:08, "JohnQ" <johnqREMOVETHI Sprogram...@yah oo.comwrote:
                    "Gavin Deane" <deane_ga...@ho tmail.comwrote in message
                    news:1182599094 .172121.251220@ n2g2000hse.goog legroups.com...
                    On 23 Jun, 12:12, "JohnQ" <johnqREMOVETHI Sprogram...@yah oo.comwrote:
                    "Gavin Deane" <deane_ga...@ho tmail.comwrote in message
                    struct foo
                    {
                    void func() { i = 42; }
                    >
                    int i;
                    };
                    int main()
                    {
                    foo local_foo;
                    local_foo.func( ); // Call 1
                    >
                    foo* dynamic_foo_ptr = new foo;
                    dynamic_foo_ptr->func(); // Call 2
                    delete dynamic_foo_ptr ;
                    }
                    >
                    For call 1, the compiler knows I want to call a function (func), it
                    knows where the code for that function is (wherever it put it) and it
                    knows which object to pass the address of as the hidden "this"
                    parameter (local_foo).
                    >
                    (I wrote this section after the stuff at the end of the post)
                    >
                    The secret ingredient is: how or by what mechanism the compiler knows how to
                    pass the foo to the foo function.
                    The compiler knows it has to pass *a* pointer-to-foo to a (non-static)
                    member function of foo because there is a pointer-t-foo in the
                    parameter list. If you write

                    struct foo
                    {
                    void func();
                    void func2(int i, double d, std::string s);
                    };
                    void foo::func() { /* ... */ }
                    void foo::func2(int i, double d, std::string s) { /* ... */ }

                    however much you might be tempted to think that you've written a
                    function, func, that takes zero parameters and a function, func2, that
                    takes three parameters (an int, a double and a std::string), you
                    haven't. You've written a function, func, that takes one parameter (a
                    pointer-to-foo) and a function, func2, that takes four parameters (a
                    pointer-to-foo, an int, a double and a std::string).

                    There are only two ways you can call func:

                    my_pointer_to_f oo->func();
                    my_foo_object.f unc();

                    and, again, no matter how much you think you are calling a function
                    that takes zero arguments, you aren't. What you are doing with those
                    two statements is actually:

                    foo::func(my_po inter_to_foo);
                    foo::func(&my_f oo_object);

                    And there are only two ways you can call func2:

                    my_pointer_to_f oo->func2(my_int , my_double, my_string);
                    my_foo_object.f unc2(my_int, my_double, my_string);

                    which, similarly, is not calling a function that takes three
                    arguments, no matter how much it looks like it. Really, those two
                    statements are:

                    foo::func2(my_p ointer_to_foo, my_int, my_double, my_string);
                    foo::func2(&my_ foo_object, my_int, my_double, my_string);
                    OK, it doesn't. You say it does the
                    binding at compile time (yes?).
                    It is known at compile time which pointer-to-foo to pass to the member
                    function, yes, in exactly the same way as it is known which int,
                    double and std::string to pass in the case of func 2, and in exactly
                    the same way it is known at compile time which values to use as the
                    parameters to any function call, whether a free function or a member
                    function. It is known because the code you write states which pointer-
                    to-foo to pass to the member function. If it wasn't apparent from your
                    code, your code wouldn't compile.
                    There is no "passing of a foo to a foo func
                    at runtime" as it is "hard coded" in the compiled code (?).
                    A pointer-to-foo is passed as parameter to each (non-static) member
                    function of foo. It has to be known at compiler time *which* pointer-
                    to-foo is passed.
                    So with a free
                    store obj, it does similar and it is enough to know that the pointer to the
                    foo is "hard coded" (like where you said foo_func(&a_foo );) by the compiler
                    All that is required is that a pointer-to-foo is passed as a
                    parameter. Whether that pointer happens to point to a dynamically
                    allocated object is irrelevant.
                    and the compiler doesn't care what actual foo is being pointed to. That's it
                    (!) isn't it?
                    If I understand you corrently, then yes. The type of the parameter is
                    pointer-to-foo. If the function is invoked like

                    my_pointer_to_f oo->func();

                    then the compiler has the necessary pointer-to-foo right there and
                    that's what it passes to the function. Everything the compiler needs
                    to make the function call is in that statement (and you will note that
                    nothing about that statement tells you, me or the compiler anything
                    about whether the foo object pointed to is dynamically allocated -
                    conclusion: whether the foo object is dynamically allocated is
                    irrelevant).

                    If the function is invoked like

                    my_foo_object.f unc();

                    the compiler's job involves one tiny extra step. The type of the
                    parameter to pass to func() is pointer-to-foo, but unlike before we
                    haven't given the compiler a pointer-to-foo, we've given it a foo.
                    However, it is simplicity itself for the compiler to obtain a pointer-
                    to-foo from a foo by taking the address of the foo. And that's what it
                    does.
                    For call 2, the compiler knows I want to call a function (func - as
                    before), it knows where the code for that function is (wherever it put
                    it - exactly the same place as before) and this time it knows it has a
                    pointer to the particular foo object for which I want to invoke the
                    function func (dynamic_foo_pt r) and so it passes dynamic_foo_ptr as
                    the hidden "this" parameter.
                    >
                    I was thinking of something less simplistic than the above example. Your
                    examples show instances where it is easy to comprehend what the compiler is
                    doing. Somewhere, I thought it would be difficult for the compiler to know
                    where class objects of a given class were instantiated (or something like
                    that) so I thought there must be some kind of external mapping of class
                    objects and their functions.
                    Perhaps I confused you by first showing an example where a member
                    function was invoked on an object directly. Maybe I gave you the
                    impression that the object is what's needed to make a call to a member
                    function work. Hopefully with the above I've made it clear that what
                    the compiler needs whenever a member function is called is a pointer.
                    Without trying to explain any more what I was
                    thinking, I'm wondering if the examples you show above are how it works ALL
                    the time (for POD-structs with member functions).
                    How I've shown it above is how it works all the time, for all non-
                    static, non-virtual member functions of all classes (not just POD-
                    structs).

                    Are you happy that the following two examples are conceptually
                    identical and that example 2 shows how, in practice, example 1 is
                    implemented?

                    // Example 1
                    struct bar
                    {
                    void reset_i();
                    void set_i(int new_value);
                    int i;
                    };

                    void bar::reset_i() { i = 0; }

                    void bar::set_i(int new_value)
                    {
                    reset_i();
                    i = new_value;
                    }

                    int main()
                    {
                    bar* pb1 = new bar;
                    pb1->set_i(100);

                    bar b1;
                    b1.set_i(42);

                    bar b2;
                    bar* pb2 = &b2;
                    pb2->set_i(5);
                    }

                    // Example 2
                    struct bar
                    {
                    int i;
                    };

                    void bar_reset_i(bar * this_) { this_->i = 0; }

                    void bar_set_i(bar* this_, int new_value)
                    {
                    bar_reset_i(thi s_);
                    this_->i = new_value;
                    }

                    int main()
                    {
                    bar* pb1 = new bar;
                    bar_set_i(pb1, 100);

                    bar b1;
                    bar_set_i(&b1, 42);

                    bar b2;
                    bar* pb2 = &b2;
                    bar_set_i(pb2, 5);
                    }

                    Gavin Deane

                    Comment

                    • JohnQ

                      #11
                      Re: How are POD structs associated with member functions?

                      (Read my response from the bottom up to avoid answering passages
                      unnecessarily. If I summed it up appropriately at the bottom of this post,
                      then there's no need to try and grok what precedes that.)

                      "Gavin Deane" <deane_gavin@ho tmail.comwrote in message
                      news:1182688831 .203295.162180@ q75g2000hsh.goo glegroups.com.. .
                      On 24 Jun, 05:08, "JohnQ" <johnqREMOVETHI Sprogram...@yah oo.comwrote:
                      >"Gavin Deane" <deane_ga...@ho tmail.comwrote in message
                      >news:118259909 4.172121.251220 @n2g2000hse.goo glegroups.com.. .
                      On 23 Jun, 12:12, "JohnQ" <johnqREMOVETHI Sprogram...@yah oo.comwrote:
                      >"Gavin Deane" <deane_ga...@ho tmail.comwrote in message
                      struct foo
                      {
                      void func() { i = 42; }
                      >>
                      int i;
                      };
                      int main()
                      {
                      foo local_foo;
                      local_foo.func( ); // Call 1
                      >>
                      foo* dynamic_foo_ptr = new foo;
                      dynamic_foo_ptr->func(); // Call 2
                      delete dynamic_foo_ptr ;
                      }
                      >>
                      For call 1, the compiler knows I want to call a function (func), it
                      knows where the code for that function is (wherever it put it) and it
                      knows which object to pass the address of as the hidden "this"
                      parameter (local_foo).
                      >>
                      >(I wrote this section after the stuff at the end of the post)
                      >>
                      >The secret ingredient is: how or by what mechanism the compiler knows how
                      >to
                      >pass the foo to the foo function.
                      >
                      The compiler knows it has to pass *a* pointer-to-foo to a (non-static)
                      member function of foo because there is a pointer-t-foo in the
                      parameter list. If you write
                      >
                      struct foo
                      {
                      void func();
                      void func2(int i, double d, std::string s);
                      };
                      void foo::func() { /* ... */ }
                      void foo::func2(int i, double d, std::string s) { /* ... */ }
                      >
                      however much you might be tempted to think that you've written a
                      function, func, that takes zero parameters and a function, func2, that
                      takes three parameters (an int, a double and a std::string), you
                      haven't. You've written a function, func, that takes one parameter (a
                      pointer-to-foo) and a function, func2, that takes four parameters (a
                      pointer-to-foo, an int, a double and a std::string).
                      That was never the question. The question is how those things are associated
                      once again after they've been separated.
                      >
                      It is known at compile time which pointer-to-foo to pass to the member
                      function, yes, in exactly the same way as it is known which int,
                      double and std::string to pass in the case of func 2, and in exactly
                      the same way it is known at compile time which values to use as the
                      parameters to any function call, whether a free function or a member
                      function. It is known because the code you write states which pointer-
                      to-foo to pass to the member function. If it wasn't apparent from your
                      code, your code wouldn't compile.
                      I'm still able to use the dot and -on a struct with apparently no member
                      functions because the size of it is the size of only the data members. So
                      there must be some magic going on to enable that to work.
                      >and the compiler doesn't care what actual foo is being pointed to. That's
                      >it
                      >(!) isn't it?
                      >
                      If I understand you corrently, then yes. The type of the parameter is
                      pointer-to-foo. If the function is invoked like
                      >
                      my_pointer_to_f oo->func();
                      Theoretically though, that shouldn't work because the compiler turned the
                      struct with member functions into a struct and separate functions taking the
                      hidden this argument. Is there some operator overloading going on?:

                      something_like_ a_class& operator->(foo&); // returns something internal that
                      works with ->
                      >
                      then the compiler has the necessary pointer-to-foo right there and
                      that's what it passes to the function. Everything the compiler needs
                      to make the function call is in that statement (and you will note that
                      nothing about that statement tells you, me or the compiler anything
                      about whether the foo object pointed to is dynamically allocated -
                      conclusion: whether the foo object is dynamically allocated is
                      irrelevant).
                      The key thing though has not yet been revealed.
                      >Without trying to explain any more what I was
                      >thinking, I'm wondering if the examples you show above are how it works
                      >ALL
                      >the time (for POD-structs with member functions).
                      >
                      How I've shown it above is how it works all the time, for all non-
                      static, non-virtual member functions of all classes (not just POD-
                      structs).
                      I am emphasizing POD-structs because they can't have a vptr. The disconnect
                      that I have is how I can call a member function from an object instance with
                      the dot or -operator when the struct is just a POD and what trickery the
                      compiler does do make sizeof(my_struc t) the size of a POD instead of size of
                      something with a vptr. The second part of that is probably easy: the
                      compiler generates a struct and separate function from my definition of the
                      POD-struct w/member functions. So if those member functions are separated
                      from the struct, how is it that dot or -can work to call a member function
                      that isn't part of the struct anymore?
                      >
                      Are you happy that the following two examples are conceptually
                      identical and that example 2 shows how, in practice, example 1 is
                      implemented?
                      Sure. That was never a question really. How that is done is what I want to
                      know. LOL, I'm talking myself into circles! I think I know the answer but I
                      forget it continually almost as soon as I learn it. At the following line in
                      my code:

                      foo.foo_func();

                      the compiler generates in the machine code, the equivalent of:

                      foo_func(&foo);

                      Therefor, there is no mechanism that associates foo structs with foo member
                      functions. It's all done by code generation. And the struct returns the size
                      of the contained sum of the sizes of it's data members because the struct
                      and member functions do indeed get separated by the compiler in the machine
                      code. And classes are handled the same way except for classes with virtual
                      functions which requires the introduction of the vptr into the data struct.


                      John

                      Comment

                      • =?ISO-8859-1?Q?Erik_Wikstr=F6m?=

                        #12
                        Re: How are POD structs associated with member functions?

                        On 2007-06-26 10:27, JohnQ wrote:
                        (Read my response from the bottom up to avoid answering passages
                        unnecessarily. If I summed it up appropriately at the bottom of this post,
                        then there's no need to try and grok what precedes that.)
                        >
                        "Gavin Deane" <deane_gavin@ho tmail.comwrote in message
                        news:1182688831 .203295.162180@ q75g2000hsh.goo glegroups.com.. .
                        >On 24 Jun, 05:08, "JohnQ" <johnqREMOVETHI Sprogram...@yah oo.comwrote:
                        >>"Gavin Deane" <deane_ga...@ho tmail.comwrote in message
                        >>news:11825990 94.172121.25122 0@n2g2000hse.go oglegroups.com. ..
                        >On 23 Jun, 12:12, "JohnQ" <johnqREMOVETHI Sprogram...@yah oo.comwrote:
                        >>"Gavin Deane" <deane_ga...@ho tmail.comwrote in message
                        >struct foo
                        >{
                        > void func() { i = 42; }
                        >>>
                        > int i;
                        >};
                        >int main()
                        >{
                        > foo local_foo;
                        > local_foo.func( ); // Call 1
                        >>>
                        > foo* dynamic_foo_ptr = new foo;
                        > dynamic_foo_ptr->func(); // Call 2
                        > delete dynamic_foo_ptr ;
                        >}
                        >>>
                        >For call 1, the compiler knows I want to call a function (func), it
                        >knows where the code for that function is (wherever it put it) and it
                        >knows which object to pass the address of as the hidden "this"
                        >parameter (local_foo).
                        >>>
                        >>(I wrote this section after the stuff at the end of the post)
                        >>>
                        >>The secret ingredient is: how or by what mechanism the compiler knows how
                        >>to
                        >>pass the foo to the foo function.
                        >>
                        >The compiler knows it has to pass *a* pointer-to-foo to a (non-static)
                        >member function of foo because there is a pointer-t-foo in the
                        >parameter list. If you write
                        >>
                        >struct foo
                        >{
                        > void func();
                        > void func2(int i, double d, std::string s);
                        >};
                        >void foo::func() { /* ... */ }
                        >void foo::func2(int i, double d, std::string s) { /* ... */ }
                        >>
                        >however much you might be tempted to think that you've written a
                        >function, func, that takes zero parameters and a function, func2, that
                        >takes three parameters (an int, a double and a std::string), you
                        >haven't. You've written a function, func, that takes one parameter (a
                        >pointer-to-foo) and a function, func2, that takes four parameters (a
                        >pointer-to-foo, an int, a double and a std::string).
                        >
                        That was never the question. The question is how those things are associated
                        once again after they've been separated.
                        >
                        >>
                        >It is known at compile time which pointer-to-foo to pass to the member
                        >function, yes, in exactly the same way as it is known which int,
                        >double and std::string to pass in the case of func 2, and in exactly
                        >the same way it is known at compile time which values to use as the
                        >parameters to any function call, whether a free function or a member
                        >function. It is known because the code you write states which pointer-
                        >to-foo to pass to the member function. If it wasn't apparent from your
                        >code, your code wouldn't compile.
                        >
                        I'm still able to use the dot and -on a struct with apparently no member
                        functions because the size of it is the size of only the data members. So
                        there must be some magic going on to enable that to work.
                        >
                        >>and the compiler doesn't care what actual foo is being pointed to. That's
                        >>it
                        >>(!) isn't it?
                        >>
                        >If I understand you corrently, then yes. The type of the parameter is
                        >pointer-to-foo. If the function is invoked like
                        >>
                        >my_pointer_to_ foo->func();
                        >
                        Theoretically though, that shouldn't work because the compiler turned the
                        struct with member functions into a struct and separate functions taking the
                        hidden this argument. Is there some operator overloading going on?:
                        >
                        something_like_ a_class& operator->(foo&); // returns something internal that
                        works with ->
                        >
                        >>
                        >then the compiler has the necessary pointer-to-foo right there and
                        >that's what it passes to the function. Everything the compiler needs
                        >to make the function call is in that statement (and you will note that
                        >nothing about that statement tells you, me or the compiler anything
                        >about whether the foo object pointed to is dynamically allocated -
                        >conclusion: whether the foo object is dynamically allocated is
                        >irrelevant).
                        >
                        The key thing though has not yet been revealed.
                        >
                        >>Without trying to explain any more what I was
                        >>thinking, I'm wondering if the examples you show above are how it works
                        >>ALL
                        >>the time (for POD-structs with member functions).
                        >>
                        >How I've shown it above is how it works all the time, for all non-
                        >static, non-virtual member functions of all classes (not just POD-
                        >structs).
                        >
                        I am emphasizing POD-structs because they can't have a vptr. The disconnect
                        that I have is how I can call a member function from an object instance with
                        the dot or -operator when the struct is just a POD and what trickery the
                        compiler does do make sizeof(my_struc t) the size of a POD instead of size of
                        something with a vptr. The second part of that is probably easy: the
                        compiler generates a struct and separate function from my definition of the
                        POD-struct w/member functions. So if those member functions are separated
                        from the struct, how is it that dot or -can work to call a member function
                        that isn't part of the struct anymore?
                        >
                        >>
                        >Are you happy that the following two examples are conceptually
                        >identical and that example 2 shows how, in practice, example 1 is
                        >implemented?
                        >
                        Sure. That was never a question really. How that is done is what I want to
                        know. LOL, I'm talking myself into circles! I think I know the answer but I
                        forget it continually almost as soon as I learn it. At the following line in
                        my code:
                        >
                        foo.foo_func();
                        >
                        the compiler generates in the machine code, the equivalent of:
                        >
                        foo_func(&foo);
                        >
                        Therefor, there is no mechanism that associates foo structs with foo member
                        functions. It's all done by code generation. And the struct returns the size
                        of the contained sum of the sizes of it's data members because the struct
                        and member functions do indeed get separated by the compiler in the machine
                        code. And classes are handled the same way except for classes with virtual
                        functions which requires the introduction of the vptr into the data struct.
                        I'm sorry, you kind of lost me here. Up till this last part it seems
                        like you don't get it and you ask how it's done. And now it seems you do
                        get it so I'm not sure if there's still something that you don't
                        understand. Please clarify.

                        --
                        Erik Wikström

                        Comment

                        • JohnQ

                          #13
                          Re: How are POD structs associated with member functions?


                          "Erik Wikström" <Erik-wikstrom@telia. comwrote in message
                          news:zx4gi.2958 $ZA.1316@newsb. telia.net...
                          On 2007-06-26 10:27, JohnQ wrote:
                          >(Read my response from the bottom up to avoid answering passages
                          >unnecessaril y. If I summed it up appropriately at the bottom of this
                          >post, then there's no need to try and grok what precedes that.)
                          >>
                          >"Gavin Deane" <deane_gavin@ho tmail.comwrote in message
                          >news:118268883 1.203295.162180 @q75g2000hsh.go oglegroups.com. ..
                          >>On 24 Jun, 05:08, "JohnQ" <johnqREMOVETHI Sprogram...@yah oo.comwrote:
                          >>>"Gavin Deane" <deane_ga...@ho tmail.comwrote in message
                          >>>news:1182599 094.172121.2512 20@n2g2000hse.g ooglegroups.com ...
                          >>On 23 Jun, 12:12, "JohnQ" <johnqREMOVETHI Sprogram...@yah oo.com>
                          >>wrote:
                          >>>"Gavin Deane" <deane_ga...@ho tmail.comwrote in message
                          >>struct foo
                          >>{
                          >> void func() { i = 42; }
                          >>>>
                          >> int i;
                          >>};
                          >>int main()
                          >>{
                          >> foo local_foo;
                          >> local_foo.func( ); // Call 1
                          >>>>
                          >> foo* dynamic_foo_ptr = new foo;
                          >> dynamic_foo_ptr->func(); // Call 2
                          >> delete dynamic_foo_ptr ;
                          >>}
                          >>>>
                          >>For call 1, the compiler knows I want to call a function (func), it
                          >>knows where the code for that function is (wherever it put it) and it
                          >>knows which object to pass the address of as the hidden "this"
                          >>parameter (local_foo).
                          >>>>
                          >>>(I wrote this section after the stuff at the end of the post)
                          >>>>
                          >>>The secret ingredient is: how or by what mechanism the compiler knows
                          >>>how
                          >>>to
                          >>>pass the foo to the foo function.
                          >>>
                          >>The compiler knows it has to pass *a* pointer-to-foo to a (non-static)
                          >>member function of foo because there is a pointer-t-foo in the
                          >>parameter list. If you write
                          >>>
                          >>struct foo
                          >>{
                          >> void func();
                          >> void func2(int i, double d, std::string s);
                          >>};
                          >>void foo::func() { /* ... */ }
                          >>void foo::func2(int i, double d, std::string s) { /* ... */ }
                          >>>
                          >>however much you might be tempted to think that you've written a
                          >>function, func, that takes zero parameters and a function, func2, that
                          >>takes three parameters (an int, a double and a std::string), you
                          >>haven't. You've written a function, func, that takes one parameter (a
                          >>pointer-to-foo) and a function, func2, that takes four parameters (a
                          >>pointer-to-foo, an int, a double and a std::string).
                          >>
                          >That was never the question. The question is how those things are
                          >associated once again after they've been separated.
                          >>
                          >>>
                          >>It is known at compile time which pointer-to-foo to pass to the member
                          >>function, yes, in exactly the same way as it is known which int,
                          >>double and std::string to pass in the case of func 2, and in exactly
                          >>the same way it is known at compile time which values to use as the
                          >>parameters to any function call, whether a free function or a member
                          >>function. It is known because the code you write states which pointer-
                          >>to-foo to pass to the member function. If it wasn't apparent from your
                          >>code, your code wouldn't compile.
                          >>
                          >I'm still able to use the dot and -on a struct with apparently no
                          >member functions because the size of it is the size of only the data
                          >members. So there must be some magic going on to enable that to work.
                          >>
                          >>>and the compiler doesn't care what actual foo is being pointed to.
                          >>>That's
                          >>>it
                          >>>(!) isn't it?
                          >>>
                          >>If I understand you corrently, then yes. The type of the parameter is
                          >>pointer-to-foo. If the function is invoked like
                          >>>
                          >>my_pointer_to _foo->func();
                          >>
                          >Theoreticall y though, that shouldn't work because the compiler turned the
                          >struct with member functions into a struct and separate functions taking
                          >the hidden this argument. Is there some operator overloading going on?:
                          >>
                          >something_like _a_class& operator->(foo&); // returns something internal
                          >that works with ->
                          >>
                          >>>
                          >>then the compiler has the necessary pointer-to-foo right there and
                          >>that's what it passes to the function. Everything the compiler needs
                          >>to make the function call is in that statement (and you will note that
                          >>nothing about that statement tells you, me or the compiler anything
                          >>about whether the foo object pointed to is dynamically allocated -
                          >>conclusion: whether the foo object is dynamically allocated is
                          >>irrelevant) .
                          >>
                          >The key thing though has not yet been revealed.
                          >>
                          >>>Without trying to explain any more what I was
                          >>>thinking, I'm wondering if the examples you show above are how it works
                          >>>ALL
                          >>>the time (for POD-structs with member functions).
                          >>>
                          >>How I've shown it above is how it works all the time, for all non-
                          >>static, non-virtual member functions of all classes (not just POD-
                          >>structs).
                          >>
                          >I am emphasizing POD-structs because they can't have a vptr. The
                          >disconnect that I have is how I can call a member function from an object
                          >instance with the dot or -operator when the struct is just a POD and
                          >what trickery the compiler does do make sizeof(my_struc t) the size of a
                          >POD instead of size of something with a vptr. The second part of that is
                          >probably easy: the compiler generates a struct and separate function from
                          >my definition of the POD-struct w/member functions. So if those member
                          >functions are separated from the struct, how is it that dot or -can
                          >work to call a member function that isn't part of the struct anymore?
                          >>
                          >>>
                          >>Are you happy that the following two examples are conceptually
                          >>identical and that example 2 shows how, in practice, example 1 is
                          >>implemented ?
                          >>
                          >Sure. That was never a question really. How that is done is what I want
                          >to know. LOL, I'm talking myself into circles! I think I know the answer
                          >but I forget it continually almost as soon as I learn it. At the
                          >following line in my code:
                          >>
                          >foo.foo_func() ;
                          >>
                          >the compiler generates in the machine code, the equivalent of:
                          >>
                          >foo_func(&foo) ;
                          >>
                          >Therefor, there is no mechanism that associates foo structs with foo
                          >member functions. It's all done by code generation. And the struct
                          >returns the size of the contained sum of the sizes of it's data members
                          >because the struct and member functions do indeed get separated by the
                          >compiler in the machine code. And classes are handled the same way except
                          >for classes with virtual functions which requires the introduction of the
                          >vptr into the data struct.
                          >
                          I'm sorry, you kind of lost me here. Up till this last part it seems like
                          you don't get it and you ask how it's done. And now it seems you do get it
                          so I'm not sure if there's still something that you don't understand.
                          Please clarify.
                          That's why I put the parenthetical text at the top of the post: I left my
                          thought process in the post just because. The key was in thinking like a
                          compiler instead of a coder. Developers tend to think in terms of mechanisms
                          (at least I do) instead of code generation, so the "how" wasn't apparent,
                          but is now. There is no C++ after the compiler gets at the code in this case
                          as it turns it all into C stuff pretty much where there is no "physical"
                          mechanism of association between the data struct and the member functions
                          (no overloaded operators or such).

                          John

                          Comment

                          • Gavin Deane

                            #14
                            Re: How are POD structs associated with member functions?

                            On 26 Jun, 09:57, Erik Wikström <Erik-wikst...@telia. comwrote:
                            On 2007-06-26 10:27, JohnQ wrote:
                            (Read my response from the bottom up to avoid answering passages
                            unnecessarily. If I summed it up appropriately at the bottom of this post,
                            then there's no need to try and grok what precedes that.)
                            <snip>
                            Therefor, there is no mechanism that associates foo structs with foo member
                            functions. It's all done by code generation. And the struct returns thesize
                            of the contained sum of the sizes of it's data members because the struct
                            and member functions do indeed get separated by the compiler in the machine
                            code. And classes are handled the same way except for classes with virtual
                            functions which requires the introduction of the vptr into the data struct.
                            >
                            I'm sorry, you kind of lost me here. Up till this last part it seems
                            like you don't get it and you ask how it's done. And now it seems you do
                            get it so I'm not sure if there's still something that you don't
                            understand. Please clarify.
                            I think John did sum it appropriately at the bottom of his post,
                            therefore his opening comment about not needing to try and grok the
                            rest of his post applies.

                            Gavin Deane



                            Comment

                            Working...