Sign in to follow this  

Functors: Why does this work?

This topic is 2633 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

Edit: The post a bit down is much more clear.

I'm using the following functor class:


class AFunctorBase
{
public:
virtual void call()=0;
virtual ~AFunctorBase(){}
};

template<typename T>
class AFunctor : public AFunctorBase
{
public:
AFunctor(T* pObject, void(T::*pFunc)())
{
m_pObject = pObject;
m_pFunc = pFunc;
}

virtual ~AFunctor(){}

virtual void call()
{
(*m_pObject.*m_pFunc)();
}
private:
void(T::*m_pFunc)();
T* m_pObject;
};








Say I have two other classes:


class A
{
public:
virtual void do_crazy_thangs() { std::cout<<"Class A"<<std::endl;
void CreateFunctor();
private:
AFunctor* m_pFunctor;
};

void A::CreateFunctor()
{
m_pFunctor = new AFunctor<A>(this, &A::do_crazy_thangs());
}

class B : public A
{
public:
virtual void do_crazy_thangs() { std::cout<<"Class B"<<std::endl;
};








Then class B calls CreateFunctor();


CreateFunctor();

// and

m_pFunctor->call();







This prints "Class B".

Mind you the actual context of the problem was much more complicated, but I spent a pretty good chunk of time trying to figure out how I was going to achieve derived functionality in do_crazy_thangs() when in order to create a functor I have to actually specify the class type to which the function being called belongs, and the address of that function. I thought that it would call that precise function regardless of inheritance. It does not, "Class B" prints. The only way I could have possibly been happier about this would have been if I had just tried it 2 hours earlier instead of trying to figure out how to accommodate a situation that didn't actually exist.

Still, I don't fully understand why it works. Is making a function call via a functor no different than making the call via somePointerToObject->do_crazy_thangs(); ? Does the compiler look at the function in some lookup table the same way it would ordinarily and realize that it is virtual and there is a derived function? Is it specifically because I pass the 'this' pointer to create the Functor? If that is the case what purpose does the functor really have for the class of the object?

Sorry if the question is confusing, but it's bugging me.

Thanks.

[Edited by - Aztral on September 30, 2010 2:29:46 AM]

Share this post


Link to post
Share on other sites
There's no way that code works. `instigator' and `args' are not defined, and there is no `this' in `main'.

How about you post actual code that compiles and runs, so we know what we are talking about?

Share this post


Link to post
Share on other sites
My apologies I forgot to edit those out. The actual code that compiles and runs is significantly longer and would make the question more convoluted, but I can post that if I have made any other stupid errors in the original post that make it not make sense.

Share this post


Link to post
Share on other sites
Quote:
Original post by Aztral
Is this more clear?

I spent some time trying to understand the code you posted originally, then the corrected version, and it still didn't make any sense. I am not going to try to read what you just posted. When you have a program that I can compile and run, I'll know that the program will make sense, and then I'll read it.

Quote:
I can't get this into a running program that will fit in a post. If not, I'll write a simple thing that runs.

It shouldn't take more than another 20 or 30 lines to get the code you originally posted to work. I would do it myself, except I don't really understand what you are doing.

Share this post


Link to post
Share on other sites
I thought this would take longer than it did:


#include<iostream>

class AFunctorBase
{
public:
virtual void call()=0;
virtual ~AFunctorBase(){}
};

template<typename T>
class AFunctor : public AFunctorBase
{
public:
AFunctor(T* pObject, void(T::*pFunc)())
{
m_pObject = pObject;
m_pFunc = pFunc;
}

virtual ~AFunctor(){}

virtual void call()
{
(*m_pObject.*m_pFunc)();
}
private:
void(T::*m_pFunc)();
T* m_pObject;
};

class A
{
public:
A() { }
~A(){}
virtual void doStuff() { std::cout<<"Class A"<<std::endl; }
void createFunctor() { pFunctor = new AFunctor<A>(this, &A::doStuff); }
AFunctorBase* pFunctor;
};

class B : public A
{
public:
B() {}
~B() {}
virtual void doStuff() { std::cout<<"Class B"<<std::endl; }
};

int main(int args, char** argc)
{
B b;
b.createFunctor();
b.pFunctor->call();
}





To restate the question, I thought (obviously incorrectly) that since in order to use a member function function pointer you must specify the class type that it belongs to the function belonging to that class, not the derived class, would have been called, and I'm wondering how, or why that is not the case.

Share this post


Link to post
Share on other sites
That's much better. You probably noticed that you couldn't make m_pFunctor private, that you didn't close some brackets, that you didn't specify `<A>' in the type of m_pFunctor, etc.

A pointer to a member function is a funny thing, and I am not entirely sure how the compiler implements it (I will check with g++), but in the case of a virtual function, it will still do the virtual dispatch.

Share this post


Link to post
Share on other sites
I checked the unoptimized assembly output of g++ for `call()', and it looks like a pointer to member function is represented by a single integer, and the last bit of the integer is set to indicate this is a virtual function. The code for `call()' checks this lowest bit and does the dispatching differently depending on what it is.

Share this post


Link to post
Share on other sites

This topic is 2633 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.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this