3

I am using function pointer in my project, facing problem, created a test case to show it... below code fail with below error on MSVC2005 (in simple words i want to access dervied class function through base class function pointer)

error C2440: '=' : cannot convert from 'void (__thiscall ClassB::* )(void)' to 'ClassAFoo'

class ClassA {
 public: 
    virtual void foo() 
    {
       printf("Foo Parent"); 
    }
};

typedef void (ClassA::*ClassAFoo)();

class ClassB : public ClassA {
 public:
    virtual void foo() 
    { 
        printf("Foo Derived"); 
    }
};

int main() {
    ClassAFoo fPtr;
    fPtr = &ClassB::foo;
}

My questions are

  1. Is it C++ behavior that I cant access derived class function through a base class function pointer or its a compiler bug?
  2. I have been playing with above case, if i comment out ClassB::foo, this code compile fine, without any further modification, Why is this so, should not fPtr = &ClassB::foo; again result in compile time error?
masoud
  • 55,379
  • 16
  • 141
  • 208
Saqlain
  • 17,490
  • 4
  • 27
  • 33
  • possible duplicate of [why can't I cast a pointer to Derived class member function to the same but of class Base?](http://stackoverflow.com/questions/10162823/why-cant-i-cast-a-pointer-to-derived-class-member-function-to-the-same-but-of-c) – John Zwinck Apr 12 '13 at 12:16
  • @JohnZwinck can you please explain it little bit? – Saqlain Apr 12 '13 at 13:20

3 Answers3

5
  1. It's correct behaviour. Think of it this way: all instances of ClassB have the member ClassA::foo, but not all instances of ClassA have the member ClassB::foo; only those instances of ClassA which are actually the base class subobject of a ClassB instance have it. Therefore, assigning ClassB::foo into ClassAFoo and then using ClassAFoo in combination with a "pure" ClassA object would try to call a nonexistent function.

  2. If you remove foo from ClassB, the expression ClassB::foo acutally refers to ClassA::foo which is inherited in ClassB, so there's no problem there.

To elaborate on 1. further: pointers to members actually work the opposite way to normal pointers. With a normal pointer, you can assign ClassB* into ClassA* (because all instances of ClassB are also instances of ClassA), but not vice versa. With member pointers, you can assign ClassA::* into ClassB::* (because ClassB contains all the members of ClassA), but not vice versa.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
3

Yes, it's ok. You cannot assign to function pointer of class A function pointer of class B. You can do this

fPtr = &ClassA::foo;
ClassB b;
classA* a = &b;
(a->*fPtr)();

and overriden in ClassB function will be called.

When there is no function foo in ClassB, function of ClassA will be used. Live example

ForEveR
  • 55,233
  • 2
  • 119
  • 133
0

First of all, I am not a C++ expert (I am trying to learn C++ so deep). So correct me if I am wrong and this an an experiment.

As part of learning about member function pointers, I was also searching for a code sample to call derived member using a base member function pointer. After going through this thread I created a code sample which is able to call derived member function even if member function is not a virtual.

I am using a Delegator to act as a Invoker. I hope it might helpful for some one. (Correct me If I am doing anything wrong)

class AbstractBase
{
protected:
    AbstractBase()
    {};

    virtual ~AbstractBase()
    {};

public:
    //Place holder method
    void SimpleMethod(void)
    {
        printf_s("\nAbstractBase::SimpleMethod");
    };
};

class Derived : public AbstractBase
{
public:
    //This overridden but not virtual.
    void SimpleMethod(void)
    {
        printf_s("Derived::SimpleMethod");
    };
};

typedef void (AbstractBase::*SimpleMethodCallback)();

class Delegator
{
private:
    AbstractBase * pbasePtr;
    SimpleMethodCallback pCallback;

public:
    Delegator()
    {
        this->pbasePtr = nullptr;
        this->pCallback = nullptr;
    };

    void RegisterCallback(AbstractBase * pbasePtr, SimpleMethodCallback callback)
    {
        if (pbasePtr == nullptr || callback == nullptr)
            throw "Delegate target or callback cannot be null";

        this->pbasePtr = pbasePtr;
        this->pCallback = callback;
    };

    void Invoke()
    {
        if (this->pbasePtr == nullptr || this->pCallback == nullptr)
            throw "Inoke cannot be performed on null target or callback";
        (pbasePtr->*pCallback)();
    }
};


int _tmain(int argc, _TCHAR* argv[])
{
    Delegator delegate;
    delegate.RegisterCallback(new Derived(), reinterpret_cast<SimpleMethodCallback>(&Derived::SimpleMethod));

    delegate.Invoke();

    return 0;
}

output:

delegate.Invoke() will call Derived::SimpleMethod() and the output will be "Derived::SimpleMethod"**

Nitheesh George
  • 1,357
  • 10
  • 13