Skip to main content
GameDev.net gamedev.net
🔒 Locked

Pointers to functions

Started by Zeraan Nov 30, 2005 at 11:24 AM 8 replies 1.3k views
Original Post
Zeraan
Zeraan
Alright, I'm working on a binary tree implementation. Since so far I have the sorting and add nodes done. I want to make a LNR function that allows pointers to functions for flexibility in manipulating the data inside. I've looked over the articles, but I didn't get it. Here's what I have so far:

//Declaration
void LNR(void(*FP)(Node*)); //In BTree class

//Definition
void BTree::LNR(void(*FP)(Node*))
{
	BTree(Root->Left).LNR(FP);
	FP(Root);
	BTree(Root->Right).LNR(FP);
}
The above compiles, but when I try to call it via this:

int main()
{
	BTree Tree;

	for(int i = 0; i < 20; i++)
	{
		Tree.Add(rand()%100);
	}

	Tree.LNR(Tree.Display);

	return 0;
}
It returns an error: error C2664: 'BTree::LNR' : cannot convert parameter 1 from 'void (void)' to 'void (__cdecl *)(Node *)' Did I did the calling part wrong, or did I do the function wrong?
tychon
tychon
I believe the issue is you're passing a class method and not a plain ol' function. I think the parameter would have to be void (Tree::*FP)(Node*) instead.

Correct me if I'm wrong, as always.
rKallmeyer
rKallmeyer
It looks like the calling part is wrong. Assuming that Display is static, and has the same signature as LNR, then you need to call it like this

Tree.LNR(Tree::Display);


If Display is not static then you need to change the definition of LNR to work with pointer-to-member functions.

This Link really helped me understand everything there is know about function pointers.
SirLuthor
SirLuthor
Try the following code out. It's been a while since I messed with pointers to member functions, so I may have made one or two mistakes. And soon someone's going to come along and pimp boost::function and boost::bind. Not my cup of tea. But anyway:

//Declarationvoid LNR(void(BTree::*FP)(Node*)); //In BTree class//Definitionvoid BTree::LNR(void(BTree::*FP)(Node*)){	BTree(Root->Left).LNR(FP);	FP(Root);	BTree(Root->Right).LNR(FP);}int main(){	BTree Tree;	for(int i = 0; i < 20; i++)		Tree.Add(rand()%100);	Tree.LNR(&Tree.Display);	return 0;}


The two mistakes I noted and fixed (I think) were, firstly, as pointed out by tychon, your function expected a normal function pointer, not a pointer to member function. Secondly, if I recall correctly, to get the address of a member function as a function pointer, in this case to pass as an argument, you always need to use the '&' symbol in front of it, unlike with simple non-member function pointers, where it should be used but is not required. Cheers!
Free speech for the living, dead men tell no tales,Your laughing finger will never point again...Omerta!Sing for me now!
Zeraan
Zeraan
Ok, I tried those out, here's the complete source code (it's not long)
#include <iostream>using namespace std;class BTree;//////////////////////////////////////////////////////////////////// Node class//////////////////////////////////////////////////////////////////class Node{	int Data;	Node* Left;	Node* Right;public:	Node(int D, Node* L = NULL, Node* R = NULL) 		: Data(D), Left(L), Right(R) {}	friend class BTree;};//////////////////////////////////////////////////////////////////// Binary Tree class//////////////////////////////////////////////////////////////////class BTree{	Node* Root;public:	BTree(Node* R = NULL) : Root(R) {}	bool Empty() { return Root == NULL; }	void LNR(void(BTree::*FP)(Node*));		void Display();	void Add(int D); //Add new node, placing it in order};//////////////////////////////////////////////////////////////////// Main Program//////////////////////////////////////////////////////////////////int main(){	BTree Tree;	for(int i = 0; i < 20; i++)	{		Tree.Add(rand()%100);	}	Tree.LNR(&Tree.Display);	return 0;}//////////////////////////////////////////////////////////////////// Add function//////////////////////////////////////////////////////////////////void BTree::Add(int D){	/*snip*/}//////////////////////////////////////////////////////////////////// LNR using function pointer//////////////////////////////////////////////////////////////////void BTree::LNR(void(BTree::*FP)(Node*)){	BTree(Root->Left).LNR(FP);	FP(Root);	BTree(Root->Right).LNR(FP);}//////////////////////////////////////////////////////////////////// Display function//////////////////////////////////////////////////////////////////void BTree::Display(){	cout << endl << Root->Data;}


On compiling, I get those errors:
error C2276: '&' : illegal operation on bound member function expression
error C2064: term does not evaluate to a function taking 1 arguments

When I remove the "BTree::" (due to the fact that FP is not an actual function, just a pointer to point to the function that got passed into the function), I only get the first error.
rKallmeyer
rKallmeyer
Okay, list of problems:


The Display method has a different signature then the parameter method to LNR. This means the Display has different parameters. You can fix this by changing

Display(void) to Display(Node*).


You are calling a pointer to member function wrong. In the link I provided, it shows you how to do it. You can fix this by changing

FP(Root) to (this->*FP)(Root);


Your LNR does not check if Root->Left and Root->Right are valid, which means your code will either explode or loop indefinetly. You can fix this by changing
BTree(Root->Left).LNR(FP);

to

if (Root->Left != NULL) BTree(Root->Left).LNR(FP);


You are passing the Display method incorrectly to the LNR function. In c++, you pass function pointers using the scope resolution operator (::) not the dot (.). You use the name of the class, not the name of the object. You can fix this by changing

Tree.LNR(&Tree.Display);

to

Tree.LNR(&BTree::Display);


Here is version with all those changes that compiles:

#include <iostream>using namespace std;class BTree;//////////////////////////////////////////////////////////////////// Node class//////////////////////////////////////////////////////////////////class Node{	int Data;	Node* Left;	Node* Right;public:	Node(int D, Node* L = NULL, Node* R = NULL) 		: Data(D), Left(L), Right(R) {}	friend class BTree;};//////////////////////////////////////////////////////////////////// Binary Tree class//////////////////////////////////////////////////////////////////class BTree{	Node* Root;public:	BTree(Node* R = NULL) : Root(R) {}	bool Empty() { return Root == NULL; }	void LNR(void(BTree::*FP)(Node*));		void Display(Node*);	void Add(int D); //Add new node, placing it in order};//////////////////////////////////////////////////////////////////// Main Program//////////////////////////////////////////////////////////////////int main(){	BTree Tree;	for(int i = 0; i < 20; i++)	{		Tree.Add(rand()%100);	}    Tree.LNR(&BTree::Display);	return 0;}//////////////////////////////////////////////////////////////////// Add function//////////////////////////////////////////////////////////////////void BTree::Add(int D){	/*snip*/}//////////////////////////////////////////////////////////////////// LNR using function pointer//////////////////////////////////////////////////////////////////void BTree::LNR(void(BTree::*FP)(Node*)){    if (Root->Left != NULL) {	    BTree(Root->Left).LNR(FP);    }    (this->*FP)(Root);	    if (Root->Right != NULL) {        BTree(Root->Right).LNR(FP);    }}//////////////////////////////////////////////////////////////////// Display function//////////////////////////////////////////////////////////////////void BTree::Display(Node* pNode){	cout << endl << Root->Data;}




Enigma
Enigma
Tree.LNR(&Tree.Display);
should be
Tree.LNR(&BTree::Display);
You can't take a pointer to a member function bound to an instance, only to a member function in general.

FP(Root);
should be
(this->*FP)(Root);
A member function pointer is not a function pointer. It needs to be bound to an instance before you can make a call through it.

I'm not going to suggest Boost.Bind and/or Boost.Function here, despite what SirLuthor might think, because it's not clear from what you've posted that it would provide any benefit - unless you need to be able to call FP on an instance of a tree other than the one you're iterating over.

Enigma
Zeraan
Zeraan
Quote:
Original post by Nuget5555
Okay, list of problems:


The Display method has a different signature then the parameter method to LNR. This means the Display has different parameters. You can fix this by changing

Display(void) to Display(Node*).


Ah, I get it!

Quote:

You are calling a pointer to member function wrong. In the link I provided, it shows you how to do it. You can fix this by changing

FP(Root) to (this->*FP)(Root);

Ok, it works, but why? I understand that this points to the current node of which the function is being called, and it points to *FP, but why did that work instead of just FP or even (*FP)?

Quote:


Your LNR does not check if Root->Left and Root->Right are valid, which means your code will either explode or loop indefinetly. You can fix this by changing
BTree(Root->Left).LNR(FP);

to

if (Root->Left != NULL) BTree(Root->Left).LNR(FP);



Oops! Thanks for catching that!

Quote:


You are passing the Display method incorrectly to the LNR function. In c++, you pass function pointers using the scope resolution operator (::) not the dot (.). You use the name of the class, not the name of the object. You can fix this by changing

Tree.LNR(&Tree.Display);

to

Tree.LNR(&BTree::Display);



Ah, I understand that now. What it is doing is essentially taking the class BTree's member function of Display's address, then passing it onto the function, correct?

Quote:

Here is version with all those changes that compiles:

*** Source Snippet Removed ***


I fixed the last function, changed from Root-> to pNode-> Thanks, it works beautifully!
Zeraan
Zeraan
Quote:
Original post by Enigma
FP(Root);
should be
(this->*FP)(Root);
A member function pointer is not a function pointer. It needs to be bound to an instance before you can make a call through it.


Oh, that answers my question of why to use this pointer.

Thanks!
SirLuthor
SirLuthor
Quote:
Original post by Enigma
Tree.LNR(&Tree.Display);
should be
Tree.LNR(&BTree::Display);
You can't take a pointer to a member function bound to an instance, only to a member function in general.

FP(Root);
should be
(this->*FP)(Root);
A member function pointer is not a function pointer. It needs to be bound to an instance before you can make a call through it.

I'm not going to suggest Boost.Bind and/or Boost.Function here, despite what SirLuthor might think, because it's not clear from what you've posted that it would provide any benefit - unless you need to be able to call FP on an instance of a tree other than the one you're iterating over.

Enigma


Heh, whatever.. It seems to be a canned reply for member function pointer posts, someone pops in with boost and a quick example, and then leaves without actually have helped at all [grin] While often times when this happens it is a viable solution, it still doesn't help the person with the question, because he still has no clue why what he was doing was wrong in the first place... But thanks for pointing that extra stuff out Enigma, that'll teach me to post without actually looking at all the code I'm copy/pasting [grin]
Free speech for the living, dead men tell no tales,Your laughing finger will never point again...Omerta!Sing for me now!

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.