Jump to content
  • Advertisement
Sign in to follow this  
Zeraan

Pointers to functions

This topic is 4862 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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?

Share this post


Link to post
Share on other sites
Advertisement
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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:


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

//Definition
void 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!

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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;
}





Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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!

Share this post


Link to post
Share on other sites
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!

Share this post


Link to post
Share on other sites
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]

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!