Function Pointers - design question.

Discussion in 'C++' started by David Williams, Feb 5, 2006.

  1. Hi Guys, I have a couple of problems. The first is (I believe) a simple
    syntactic problem you can probably solve quite easily. The second is a
    design style problem which might be more tricky...

    So, I have a class with a couple of integers. I provide a couple of
    functions to operate on those integers (add, subtract) and the function
    to be called is chosen via a function pointer. Like so:

    01: #include <iostream>
    02:
    03: class MyClass
    04: {
    05: public:
    06: MyClass(int xToSet, int yToSet):x(xToSet), y(yToSet){};
    07:
    08: void setOperationToAdd(void)
    09: {
    10: performOperation = add;
    11: }
    12:
    13: void setOperationToSubtract(void)
    14: {
    15: performOperation = subtract;
    16: }
    17:
    18: //Pointer to an operation.
    19: int (MyClass::*performOperation)(void);
    20:
    21: protected:
    22: int add(void){return x + y;};
    23: int subtract(void){return x - y;};
    24: int x;
    25: int y;
    26: };
    27:
    28: int main()
    29: {
    30: MyClass test(10,20);
    31: test.setOperationToAdd();
    32: std::cout << test.performOperation() << std::endl;
    33: test.setOperationToSubtract();
    34: std::cout << test.performOperation() << std::endl;
    35:
    36: return 0;
    37: }

    Visual Studio gives the error:

    error C2064: term does not evaluate to a function taking 0 arguments

    for lines 32 and 34. Any idea what the problem is?

    Ok, now for the design problem. I wish to allow the user of my class to
    specify their own operations (e.g. multiply, divide). The problem I have
    is that these new functions are declared outside the class, they are not
    member functions (because presumably the user wouldn't be able to modify
    my class). Now, pointers to member functions (such as the one i've
    declared) cannot point to normal functions because of the implicit
    'this' parameter. How should I solve this?

    1) I could require my users to subclass 'MyClass' if they want to add
    new functions. Their new functions would then be members and so could be
    pointed to. This has the advantage that they can directly access the
    protected parts without accessor functions but seems a bit of a burden
    on the user.

    2) I read (briefly) about funtionoids in the FAQ's. It seens they can be
    used when functions have varying parameters as common ones get passed to
    the constructor of the functionoid and un-common ones get passed when
    the functionoid is called. Can these be used in this situation?

    Any furthers ideas?

    Thanks in advance,

    David
     
    David Williams, Feb 5, 2006
    #1
    1. Advertising

  2. David Williams

    benben Guest

    David Williams wrote:
    > Hi Guys, I have a couple of problems. The first is (I believe) a simple
    > syntactic problem you can probably solve quite easily. The second is a
    > design style problem which might be more tricky...


    My answer and opinions after your code below:

    >
    > So, I have a class with a couple of integers. I provide a couple of
    > functions to operate on those integers (add, subtract) and the function
    > to be called is chosen via a function pointer. Like so:
    >
    > 01: #include <iostream>
    > 02:
    > 03: class MyClass
    > 04: {
    > 05: public:
    > 06: MyClass(int xToSet, int yToSet):x(xToSet), y(yToSet){};
    > 07:
    > 08: void setOperationToAdd(void)
    > 09: {
    > 10: performOperation = add;
    > 11: }
    > 12:
    > 13: void setOperationToSubtract(void)
    > 14: {
    > 15: performOperation = subtract;
    > 16: }
    > 17:
    > 18: //Pointer to an operation.
    > 19: int (MyClass::*performOperation)(void);
    > 20:
    > 21: protected:
    > 22: int add(void){return x + y;};
    > 23: int subtract(void){return x - y;};
    > 24: int x;
    > 25: int y;
    > 26: };
    > 27:
    > 28: int main()
    > 29: {
    > 30: MyClass test(10,20);
    > 31: test.setOperationToAdd();
    > 32: std::cout << test.performOperation() << std::endl;
    > 33: test.setOperationToSubtract();
    > 34: std::cout << test.performOperation() << std::endl;
    > 35:
    > 36: return 0;
    > 37: }
    >
    > Visual Studio gives the error:
    >
    > error C2064: term does not evaluate to a function taking 0 arguments
    >
    > for lines 32 and 34. Any idea what the problem is?


    std::cout << (test.*(test.performOperation))()
    << std::endl;

    >
    > Ok, now for the design problem. I wish to allow the user of my class to
    > specify their own operations (e.g. multiply, divide). The problem I have
    > is that these new functions are declared outside the class, they are not
    > member functions (because presumably the user wouldn't be able to modify
    > my class). Now, pointers to member functions (such as the one i've
    > declared) cannot point to normal functions because of the implicit
    > 'this' parameter. How should I solve this?


    The design is ill-formed. Your idea can be directly expressed by better
    encapsulating MyClass. For example:

    class MyClass{
    int m_x, m_y;

    public:
    MyClass(int _x, int _y){m_x = _x; m_y = _y;}

    int x(void) const {return m_x;}
    int y(void) const {return m_y;}
    };

    int add(const MyClass& i){return i.x() + i.y();}
    int subtract(const MyClass& i){return i.x() - i.y();}


    int main(void)
    {
    MyClass test(8, 2);
    int a = add(test); // a = 10
    int b = subtract(test); // b = 6

    return 0;
    }

    >
    > 1) I could require my users to subclass 'MyClass' if they want to add
    > new functions. Their new functions would then be members and so could be
    > pointed to. This has the advantage that they can directly access the
    > protected parts without accessor functions but seems a bit of a burden
    > on the user.


    If you do this, you will have to provide virtual functions at least.
    This is unnecessary and it breaks encapsulation. The idea is to shield
    the vast amount of add-on functionality from the core, so that changing
    the core would not need a rewrite of every single add-on function.

    And plus, setting and resetting the behavior of a particular function of
    a class is not a good idea. Users can be quite confused.

    >
    > 2) I read (briefly) about funtionoids in the FAQ's. It seens they can be
    > used when functions have varying parameters as common ones get passed to
    > the constructor of the functionoid and un-common ones get passed when
    > the functionoid is called. Can these be used in this situation?


    I'm not so sure about what you mean but I guess you want an adapter to
    work your class with function objects in <functional>. This can be done
    quite easily once you have properly encapsulate your class:

    // with the same class definition I gave you:

    template <typename Op>
    int perform(const MyClass& i, Op op)
    {
    return op(i.x(), i.y());
    }

    int c = perform(test, std::plus<int>());
    int d = perform(test, std::minus<int>());

    And yes, you can add function objects to have broader use.

    >
    > Any furthers ideas?
    >
    > Thanks in advance,
    >
    > David


    Regards,
    Ben
     
    benben, Feb 5, 2006
    #2
    1. Advertising

  3. benben wrote:
    > David Williams wrote:
    >> Hi Guys, I have a couple of problems. The first is (I believe) a
    >> simple syntactic problem you can probably solve quite easily. The
    >> second is a design style problem which might be more tricky...

    >
    > My answer and opinions after your code below:
    >
    >>
    >> So, I have a class with a couple of integers. I provide a couple of
    >> functions to operate on those integers (add, subtract) and the
    >> function to be called is chosen via a function pointer. Like so:
    >>
    >> 01: #include <iostream>
    >> 02:
    >> 03: class MyClass
    >> 04: {
    >> 05: public:
    >> 06: MyClass(int xToSet, int yToSet):x(xToSet), y(yToSet){};
    >> 07:
    >> 08: void setOperationToAdd(void)
    >> 09: {
    >> 10: performOperation = add;
    >> 11: }
    >> 12:
    >> 13: void setOperationToSubtract(void)
    >> 14: {
    >> 15: performOperation = subtract;
    >> 16: }
    >> 17:
    >> 18: //Pointer to an operation.
    >> 19: int (MyClass::*performOperation)(void);
    >> 20:
    >> 21: protected:
    >> 22: int add(void){return x + y;};
    >> 23: int subtract(void){return x - y;};
    >> 24: int x;
    >> 25: int y;
    >> 26: };
    >> 27:
    >> 28: int main()
    >> 29: {
    >> 30: MyClass test(10,20);
    >> 31: test.setOperationToAdd();
    >> 32: std::cout << test.performOperation() << std::endl;
    >> 33: test.setOperationToSubtract();
    >> 34: std::cout << test.performOperation() << std::endl;
    >> 35:
    >> 36: return 0;
    >> 37: }
    >>
    >> Visual Studio gives the error:
    >>
    >> error C2064: term does not evaluate to a function taking 0 arguments
    >>
    >> for lines 32 and 34. Any idea what the problem is?

    >
    > std::cout << (test.*(test.performOperation))()
    > << std::endl;
    >
    >>
    >> Ok, now for the design problem. I wish to allow the user of my class
    >> to specify their own operations (e.g. multiply, divide). The problem I
    >> have is that these new functions are declared outside the class, they
    >> are not member functions (because presumably the user wouldn't be able
    >> to modify my class). Now, pointers to member functions (such as the
    >> one i've declared) cannot point to normal functions because of the
    >> implicit 'this' parameter. How should I solve this?

    >
    > The design is ill-formed. Your idea can be directly expressed by better
    > encapsulating MyClass. For example:
    >
    > class MyClass{
    > int m_x, m_y;
    >
    > public:
    > MyClass(int _x, int _y){m_x = _x; m_y = _y;}
    >
    > int x(void) const {return m_x;}
    > int y(void) const {return m_y;}
    > };
    >
    > int add(const MyClass& i){return i.x() + i.y();}
    > int subtract(const MyClass& i){return i.x() - i.y();}
    >
    >
    > int main(void)
    > {
    > MyClass test(8, 2);
    > int a = add(test); // a = 10
    > int b = subtract(test); // b = 6
    >
    > return 0;
    > }
    >
    >>
    >> 1) I could require my users to subclass 'MyClass' if they want to add
    >> new functions. Their new functions would then be members and so could
    >> be pointed to. This has the advantage that they can directly access
    >> the protected parts without accessor functions but seems a bit of a
    >> burden on the user.

    >
    > If you do this, you will have to provide virtual functions at least.
    > This is unnecessary and it breaks encapsulation. The idea is to shield
    > the vast amount of add-on functionality from the core, so that changing
    > the core would not need a rewrite of every single add-on function.
    >
    > And plus, setting and resetting the behavior of a particular function of
    > a class is not a good idea. Users can be quite confused.
    >
    >>
    >> 2) I read (briefly) about funtionoids in the FAQ's. It seens they can
    >> be used when functions have varying parameters as common ones get
    >> passed to the constructor of the functionoid and un-common ones get
    >> passed when the functionoid is called. Can these be used in this
    >> situation?

    >
    > I'm not so sure about what you mean but I guess you want an adapter to
    > work your class with function objects in <functional>. This can be done
    > quite easily once you have properly encapsulate your class:
    >
    > // with the same class definition I gave you:
    >
    > template <typename Op>
    > int perform(const MyClass& i, Op op)
    > {
    > return op(i.x(), i.y());
    > }
    >
    > int c = perform(test, std::plus<int>());
    > int d = perform(test, std::minus<int>());
    >
    > And yes, you can add function objects to have broader use.
    >
    >>
    >> Any furthers ideas?
    >>
    >> Thanks in advance,
    >>
    >> David

    >
    > Regards,
    > Ben


    Thanks, your code fixed the syntax problem I was having. Regarding the
    design it seems my design was somewhat flawed - the functionoid /
    function object approach does seems better. I think I'll read around it
    some more though...

    Regards,

    David
     
    David Williams, Feb 6, 2006
    #3
    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. Phil
    Replies:
    1
    Views:
    673
    llewelly
    Sep 16, 2003
  2. Peter Goddard

    void pointers & void function pointers

    Peter Goddard, May 16, 2005, in forum: C Programming
    Replies:
    3
    Views:
    533
    Peter Goddard
    May 16, 2005
  3. Chad

    pointers to pointers question

    Chad, Mar 26, 2006, in forum: C Programming
    Replies:
    5
    Views:
    329
    Default User
    Mar 27, 2006
  4. n2xssvv g02gfr12930

    Smart pointers and member function pointers

    n2xssvv g02gfr12930, Nov 26, 2005, in forum: C++
    Replies:
    3
    Views:
    502
    n2xssvv g02gfr12930
    Nov 27, 2005
  5. cerr

    pointers, pointers, pointers...

    cerr, Apr 7, 2011, in forum: C Programming
    Replies:
    12
    Views:
    739
Loading...

Share This Page