Search code examples
c++functionpointerscontravarianceupcasting

No implicit upcasting with function pointers arguments?


This is kind of a strange situation I've run into. I expected for the pointer to be implicitly upcast:

struct BaseClass
{};

struct DerivedClass : BaseClass
{};

void baseClassArgFunc(BaseClass* arg) {}            // Function taking BaseClass argument
void derivedClassArgFunc(DerivedClass* arg) {}      // Function taking DerivedClass argument

int main()
{
    void (*pBaseFuncArg) (BaseClass*);      // Pointer to function taking BaseClass argument
    void (*pDerivedFuncArg) (DerivedClass*);    // Pointer to function taking DerivedClass argument

    pBaseFuncArg = baseClassArgFunc;            // Assign pointer, works fine
    pDerivedFuncArg = derivedClassArgFunc;      // Assign pointer, works fine

    pBaseFuncArg = derivedClassArgFunc;         // A value of type void (*) (DerivedClass *arg) cannot be 
                                                // assigned to an entity of type void (*) (BaseClass *)

    pDerivedFuncArg = baseClassArgFunc;         // A value of type void (*) (BaseClass *arg) cannot be 
                                                // assigned to an entity of type void (*) (DerivedClass *)

    return 0;
}

I expected assigning void ( * ) (DerivedClass*) to void baseClassArgFunc(BaseClass* arg) to be safe. I'm confused. I guess there's no implicit upcasting with function pointer arguments then?


Solution

  • Changing your classes to expose the issues:

    struct BaseClass
    {
    };
    
    struct DerivedClass : BaseClass
    {
        int a;
    };
    

    Then

    pBaseFuncArg = derivedClassArgFunc;
    

    is unsafe for:

     void derivedClassArgFunc(DerivedClass* arg) { arg->a = 42; }
    
    
     int main()
     {
         void (*pBaseFuncArg) (BaseClass*) = derivedClassArgFunc;
         BaseClass base;
    
         //derivedClassArgFunc(&base); // Doesn't compile as expected
         pBaseFuncArg(&base);          // Would be UB, base->i won't exist
     }