Functors: Why does this work?

Started by
8 comments, last by Aztral 13 years, 6 months ago
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();// andm_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]
Advertisement
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?
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.
We don't need to see your whole program: You can just put the pieces you posted together in a simple program that compiles and runs.

See two posts down.
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.

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.
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.

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.

Thanks very much. It never hurts to understand why things work!

This topic is closed to new replies.

Advertisement