Function Pointers - design question.

D

David Williams

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
 
B

benben

David said:
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
 
D

David Williams

benben said:
My answer and opinions after your code below:


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


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;
}


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.


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.


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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,982
Messages
2,570,190
Members
46,736
Latest member
zacharyharris

Latest Threads

Top