Pointer to non-static member functions

Discussion in 'C++' started by Tim Frink, May 8, 2008.

  1. Tim Frink

    Tim Frink Guest

    Hi,

    I'm experimenting with function pointers and found
    two questions. Let's assume this code:

    1 #include <iostream>
    2 class A;
    3
    4 ////////////////////////////////////////////
    5 class B
    6 {
    7 public:
    8 void printB( void (A::*)(void) );
    9 };
    10
    11 void B::printB( void (A::*func)(void) )
    12 {
    13 *func(); // not working
    14 }
    15
    16 ////////////////////////////////////////////
    17 class A
    18 {
    19 public:
    20 void printA(void);
    21 void invokeB(void);
    22
    23 private:
    24 B myB;
    25 };
    26
    27 void A::printA(void)
    28 {
    29 std::cout << "A::print" << std::endl;
    30 return;
    31 }
    32
    33 void A::invokeB(void)
    34 {
    35 myB.printB( &A::printA );
    36 return;
    37 }
    38
    39 ////////////////////////////////////////////
    40 int main(void)
    41 {
    42 A myA;
    43 a.invokeB();
    44
    45 return 0;
    46 }

    What I want to achieve is a communication between two object
    with a callback function. Object A invokes a function in
    object B passing a callback function. The invoked function in
    object B calls the passed callback function to communicate
    with the caller A.

    So, I'm passing a pointer to A::printA in line 35 to
    B::printB. The called member function printB of object
    myB than should deference the passed function pointer
    (line 13, not working yet) to invoke again a function
    (A::printfA) of the original caller. Thus, myA invokes
    myB which in turn invokes myA again.

    My first question concerns line 35. What exactly is the
    address of &A::printA? When I forward this value to "cout",
    (cout << &A::printA) I get the output "1" and not an
    address. Since A::printA is a non-static member function,
    it cannot be considered independent of a concrete object.
    Thus, I would assume that &AA::printA is an offset which
    must be added to the memory address where a concrete
    object of class A is allocated. Adding the start address
    and the offset would result in the address where the
    function printA of an individual object of class A is
    located.

    And this brings me to my second question concerning line
    13. When I try to compiler this code, I get the compiler error:
    error: must use .* or ->* to call pointer-to-member function in `func (...)'
    I assume the problem is that the function pointer "func" has
    no reference to a concrete object of class A (myA in this case).
    So, the function cannot be invoked. How can I solve this?
    Do I have to pass the address of myA to B::printB?
    Something like "myB.printB( &A::printA, this );" in line 35
    and than use the pointer in "this" to invoke func?

    Thank you.

    Regards,
    Tim
     
    Tim Frink, May 8, 2008
    #1
    1. Advertising

  2. Tim Frink

    peter koch Guest

    On 8 Maj, 11:26, Tim Frink <> wrote:
    > Hi,
    >
    > I'm experimenting with function pointers and found
    > two questions. Let's assume this code:
    >
    >   1 #include <iostream>
    >   2 class A;
    >   3
    >   4 ////////////////////////////////////////////
    >   5 class B
    >   6 {
    >   7   public:
    >   8     void printB( void (A::*)(void) );
    >   9 };
    >  10
    >  11 void B::printB( void (A::*func)(void) )
    >  12 {
    >  13   *func(); // not working
    >  14 }
    >  15
    >  16 ////////////////////////////////////////////
    >  17 class A
    >  18 {
    >  19   public:
    >  20     void printA(void);
    >  21     void invokeB(void);
    >  22
    >  23   private:
    >  24     B myB;
    >  25 };
    >  26
    >  27 void A::printA(void)
    >  28 {
    >  29   std::cout << "A::print" << std::endl;
    >  30   return;
    >  31 }
    >  32
    >  33 void A::invokeB(void)
    >  34 {
    >  35   myB.printB( &A::printA );
    >  36   return;
    >  37 }
    >  38
    >  39 ////////////////////////////////////////////
    >  40 int main(void)
    >  41 {
    >  42   A myA;
    >  43   a.invokeB();
    >  44
    >  45   return 0;
    >  46 }
    >
    > What I want to achieve is a communication between two object
    > with a callback function. Object A invokes a function in
    > object B passing a callback function. The invoked function in
    > object B calls the passed callback function to communicate
    > with the caller A.
    >
    > So, I'm passing a pointer to A::printA in line 35 to
    > B::printB. The called member function printB of object
    > myB than should deference the passed function pointer
    > (line 13, not working yet) to invoke again a function
    > (A::printfA) of the original caller. Thus, myA invokes
    > myB which in turn invokes myA again.
    >
    > My first question concerns line 35. What exactly is the
    > address of &A::printA? When I forward this value to "cout",
    > (cout << &A::printA) I get the output "1" and not an
    > address.


    Probably you did print "true" because the memberfunction is not null.
    Apart from that, I do not see what interest you could have in getting
    its adress. If it is out of curiosity, I would recommend you to
    examine the value in a debugger instead.

    > Since A::printA is a non-static member function,
    > it cannot be considered independent of a concrete object.


    Yes it can. A memberfunction is not connected to any concrete object.
    I will come back to that later.

    > Thus, I would assume that &AA::printA is an offset which
    > must be added to the memory address where a concrete
    > object of class A is allocated. Adding the start address
    > and the offset would result in the address where the
    > function printA of an individual object of class A is
    > located.


    I am not sure I can decipher the above, but if your understanding is
    that a memberfunction somehow is placed inside an object, your
    understanding is wrong. A memberfunction is does not take up any space
    in an object.
    >
    > And this brings me to my second question concerning line
    > 13. When I try to compiler this code, I get the compiler error:
    > error: must use .* or ->* to call pointer-to-member function in `func (...)'


    (repeating offensive code)
    > 11 void B::printB( void (A::*func)(void) )
    > 12 {
    > 13 *func(); // not working
    > 14 }
    > 15


    This is because your perception of a member-function pointer is wrong.
    A member-function pointer is a pointer that can be used to call a
    memberfunction oon all objects of the given type. But you have to
    provide an object. So your code should have been somewhat like:

    > 11 void B::printB( A *a, void (A::*func)(void) )
    > 12 {
    > 13 (a->*func)();
    > 14 }
    > 15



    > I assume the problem is that the function pointer "func" has
    > no reference to a concrete object of class A (myA in this case).
    > So, the function cannot be invoked. How can I solve this?
    > Do I have to pass the address of myA to B::printB?
    > Something like "myB.printB( &A::printA, this );" in line 35
    > and than use the pointer in "this" to invoke func?

    Exactly.


    /Peter
     
    peter koch, May 8, 2008
    #2
    1. Advertising

  3. Tim Frink

    Krice Guest

    Tim Frink kirjoitti:
    > How can I solve this?


    Use C-style functions. Another option is that you start programming
    in C++ and stop using function pointers.
     
    Krice, May 8, 2008
    #3
  4. On May 8, 11:26 am, Tim Frink <> wrote:
    > What I want to achieve is a communication between two object
    > with a callback function. Object A invokes a function in
    > object B passing a callback function. The invoked function in
    > object B calls the passed callback function to communicate
    > with the caller A.


    You might want to check out the visitor design pattern to achieve the
    same effect.

    Best Regards,
    Szabolcs
     
    Szabolcs Ferenczi, May 8, 2008
    #4
  5. Tim Frink

    James Kanze Guest

    > I'm experimenting with function pointers and found
    > two questions. Let's assume this code:


    > 1 #include <iostream>
    > 2 class A;


    > 4 ////////////////////////////////////////////
    > 5 class B
    > 6 {
    > 7 public:
    > 8 void printB( void (A::*)(void) );
    > 9 };
    > 10
    > 11 void B::printB( void (A::*func)(void) )
    > 12 {
    > 13 *func(); // not working


    That's because you need an object on which to call the function.

    > 14 }
    > 15
    > 16 ////////////////////////////////////////////
    > 17 class A
    > 18 {
    > 19 public:
    > 20 void printA(void);
    > 21 void invokeB(void);


    > 23 private:
    > 24 B myB;
    > 25 };


    > 27 void A::printA(void)
    > 28 {
    > 29 std::cout << "A::print" << std::endl;
    > 30 return;
    > 31 }


    > 33 void A::invokeB(void)
    > 34 {
    > 35 myB.printB( &A::printA );
    > 36 return;
    > 37 }


    > 39 ////////////////////////////////////////////
    > 40 int main(void)
    > 41 {
    > 42 A myA;
    > 43 a.invokeB();


    > 45 return 0;
    > 46 }


    > What I want to achieve is a communication between two object
    > with a callback function. Object A invokes a function in
    > object B passing a callback function. The invoked function in
    > object B calls the passed callback function to communicate
    > with the caller A.


    Are the types known to both objects? The "usual" solution here
    involves an abstract base class, something like:

    class AbstractCallback
    {
    public:
    virtual ~AbstractCallback() {}
    virtual void notify() = 0 ; // or some other name.
    } ;

    The class requesting the callback can then derive from this;
    often, you migth also provide a templated concrete derivation:

    template< typename T, void (T::*fnc)() >
    class Callback : public AbstractCallback
    {
    public:
    Callback( T* obj ) : myObj( obj ) {}
    virtual void notify()
    {
    (myObj->*fnc)() ;
    }

    private:
    T* myObj ;
    } ;

    In the absense of garbage collection, this solution requires
    some complex memory management, however.

    > So, I'm passing a pointer to A::printA in line 35 to
    > B::printB. The called member function printB of object myB
    > than should deference the passed function pointer (line 13,
    > not working yet) to invoke again a function (A::printfA) of
    > the original caller. Thus, myA invokes myB which in turn
    > invokes myA again.


    > My first question concerns line 35. What exactly is the
    > address of &A::printA?


    A pointer to member function. Which is more of a selector than
    a pointer in the real sense. At any rate, it definitely must
    contain more than just an address, since it must work with
    virtual functions (where the actual function called depends on
    the dynamic type it is being called on). If you check the
    sizeof a pointer to member function, it will typically (but not
    necessarily) be larger than a normal pointer to function.

    > When I forward this value to "cout", (cout << &A::printA) I
    > get the output "1" and not an address.


    There is no << operator defined for pointer to members. There
    is an implicit conversion of pointers to members to a bool,
    which results in true if the pointer to member is not null, and
    there is a << operator for bool.

    > Since A::printA is a non-static member function, it cannot be
    > considered independent of a concrete object. Thus, I would
    > assume that &AA::printA is an offset which must be added to
    > the memory address where a concrete object of class A is
    > allocated.


    It's more complicated than that. The class instance doesn't
    actually contain a copy of the code of its member functions; in
    many ways, the only difference between a member function and a
    non member function is that the member function has an
    additional hidden argument. The way member functions are
    called, however, is different, both in regards to syntax, and
    (at least when virtual functions are considered) the mechanics.

    > Adding the start address and the offset would result in the
    > address where the function printA of an individual object of
    > class A is located.


    No.

    > And this brings me to my second question concerning line 13.
    > When I try to compiler this code, I get the compiler error:
    > error: must use .* or ->* to call pointer-to-member function
    > in `func (...)' I assume the problem is that the function
    > pointer "func" has no reference to a concrete object of class
    > A (myA in this case). So, the function cannot be invoked. How
    > can I solve this? Do I have to pass the address of myA to
    > B::printB? Something like "myB.printB( &A::printA, this );"
    > in line 35 and than use the pointer in "this" to invoke func?


    Exactly. Or you wrap some, using an intermediate "agent" class.
    (This is generally considered the prefered solution, since it
    means that the class invoking the callback doesn't need to know
    of the class which is called back.)

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, May 9, 2008
    #5
  6. Tim Frink

    Tim Frink Guest

    >
    > Probably you did print "true" because the memberfunction is not null.


    But why did I not get the address? I though that &A::printA is a pointer.
    So, I can't understand why I get "true".

    > Apart from that, I do not see what interest you could have in getting
    > its adress. If it is out of curiosity, I would recommend you to
    > examine the value in a debugger instead.


    This was just for curiosity. When this value is passed as an
    argument, it would make sense to check if it's not 0. So I think
    that the check of the address makes sense in some situations.

    > I am not sure I can decipher the above, but if your understanding is
    > that a memberfunction somehow is placed inside an object, your
    > understanding is wrong. A memberfunction is does not take up any space
    > in an object.


    I'm not aware of the code generation for C++ programs. But from your
    post I assume that for each C++ class exactly one code (fragment) is
    allocated in the object's text section independently if and how many
    times objects of this class are instantiated. So what happens when
    an object of a particular class is instantiated? Will additional code
    be allocated in the .text section? Or will this new object be considered
    as data allocated on the stack/heap with some references to the class
    code located somewhere in the .text section?

    >> And this brings me to my second question concerning line
    >> 13. When I try to compiler this code, I get the compiler error:
    >> error: must use .* or ->* to call pointer-to-member function in `func (...)'

    >
    > (repeating offensive code)
    >> 11 void B::printB( void (A::*func)(void) )
    >> 12 {
    >> 13 *func(); // not working
    >> 14 }
    >> 15

    >
    > This is because your perception of a member-function pointer is wrong.
    > A member-function pointer is a pointer that can be used to call a
    > memberfunction oon all objects of the given type. But you have to
    > provide an object. So your code should have been somewhat like:


    So, why do I need the object and can't access the function (in my
    case func) without the object? If it's already in the memory
    (.text section) and func has the address to it, so why is the
    object still needed for the access?

    My assumption would be that an instantiated object has some references
    which point to addresses (or functions/attributes behind theses addresses)
    that is is allowed to access. So, the object code contains a sort
    of permissions about what code can be accessed and which not. Are these
    thoughts going into the right direction?

    Tim
     
    Tim Frink, May 9, 2008
    #6
  7. Tim Frink

    James Kanze Guest

    On 9 mai, 19:56, Tim Frink <> wrote:
    > > Probably you did print "true" because the memberfunction is
    > > not null.


    > But why did I not get the address? I though that &A::printA is
    > a pointer. So, I can't understand why I get "true".


    It's not a pointer, it's a pointer to member. Not the same
    thing.

    > > Apart from that, I do not see what interest you could have in getting
    > > its adress. If it is out of curiosity, I would recommend you to
    > > examine the value in a debugger instead.


    > This was just for curiosity. When this value is passed as an
    > argument, it would make sense to check if it's not 0. So I think
    > that the check of the address makes sense in some situations.


    It can make sense to check whether it is a null pointer. The
    integral constant expression 0 will convert to a null pointer to
    member in appropriate contexts. None of which has anything to
    do with "address"; a pointer to member is never an "address",
    just something which the compiler knows how to use in the
    appropriate context.

    > > I am not sure I can decipher the above, but if your
    > > understanding is that a memberfunction somehow is placed
    > > inside an object, your understanding is wrong. A
    > > memberfunction is does not take up any space in an object.


    > I'm not aware of the code generation for C++ programs. But
    > from your post I assume that for each C++ class exactly one
    > code (fragment) is allocated in the object's text section
    > independently if and how many times objects of this class are
    > instantiated.


    Exactly. The executed code is the same for all instances, so
    can be treated as if it were static, and it's not modifiable, so
    it can be treated as a const.

    > So what happens when an object of a particular class is
    > instantiated? Will additional code be allocated in the .text
    > section?


    Why? The code is the same for all instances.

    > Or will this new object be considered as data allocated on the
    > stack/heap with some references to the class code located
    > somewhere in the .text section?


    No. The only reference to the instance is the this pointer,
    passed as an additional argument when calling a member function.

    > >> And this brings me to my second question concerning line
    > >> 13. When I try to compiler this code, I get the compiler
    > >> error: error: must use .* or ->* to call pointer-to-member
    > >> function in `func (...)'


    > > (repeating offensive code)
    > >> 11 void B::printB( void (A::*func)(void) )
    > >> 12 {
    > >> 13 *func(); // not working
    > >> 14 }
    > >> 15


    > > This is because your perception of a member-function pointer
    > > is wrong. A member-function pointer is a pointer that can
    > > be used to call a member function oon all objects of the
    > > given type. But you have to provide an object. So your code
    > > should have been somewhat like:


    > So, why do I need the object and can't access the function (in
    > my case func) without the object?


    Because there's no syntax which supports it? Define first what
    you mean by "access the function". You can call the function on
    an object of an appropriate type, and you can compare the
    pointer to member with a null pointer constant or with other
    pointers to members.

    > If it's already in the memory (.text section) and func has the
    > address to it, so why is the object still needed for the
    > access?


    Because you need to initialize the this pointer in order to call
    the function. You can't call a member function without an
    object. Either directly, or through a pointer to member
    function.

    > My assumption would be that an instantiated object has some
    > references which point to addresses (or functions/attributes
    > behind theses addresses) that is is allowed to access. So, the
    > object code contains a sort of permissions about what code can
    > be accessed and which not. Are these thoughts going into the
    > right direction?


    The implementation is somewhat complicated by the presence of
    virtual functions. In practice, a non-virtual member function
    is just a regular function with an additional, invisible
    parameter: the compiler passes the address of the object as
    argument to this parameter, which becomes the this pointer in
    the function. Virtual functions are more complicated; if the
    class contains one or more virtual functions, the compiler will
    typically allocate an additional hidden pointer in the class
    member, and initialize it in the contructor to point to a table
    with the addresses of the functions for that class.

    A pointer to member function has to take this into account.
    Consider something like:

    struct Base
    {
    virtual void f() ;
    } ;

    struct Derived : Base
    {
    virtual void f() ;
    } ;

    void (Base::*pfm)() = &Base::f ;
    Base* pObj = new Derived ;
    (pObj->*pfm)() ; // calls Derived::f

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, May 10, 2008
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    9
    Views:
    956
    Ben Bacarisse
    Feb 6, 2006
  2. dolphin
    Replies:
    3
    Views:
    1,350
    Pete Becker
    Dec 5, 2007
  3. Hicham Mouline
    Replies:
    0
    Views:
    435
    Hicham Mouline
    Apr 23, 2009
  4. Hicham Mouline
    Replies:
    1
    Views:
    421
    Michael DOUBEZ
    Apr 24, 2009
  5. Stephen Howe
    Replies:
    2
    Views:
    291
    Stephen Howe
    Nov 6, 2012
Loading...

Share This Page