nikitablack
nikitablack

Reputation: 4663

Cast function pointers that differs by argument type

Why this is not legal:

class Base
{
public:
    Base(){};
    virtual ~Base(){};
};

class Derived : public Base{};

void takeDerived(Derived * c){};

// main
void(*ptr)(Base*) = static_cast<void(*)(Base*)>(&takeDerived); // doesn't work

// but this work ok, as well as reinterpret_cast
// void(*ptr)(Base*) = (void(*)(Base*))(&takeDerived);

Derived is a Base. Why can't it be casted in function parameter? For example, I can do this easily even without casting:

void takeBase(Base* c){};
takeBase(new Derived{});

Upvotes: 0

Views: 452

Answers (2)

iBug
iBug

Reputation: 37217

It's just designed to be that way. A Base isn't a Derived. The is-a relationship for class derivation can't be reversed.

The type of a function parameter means "accept", while the type of an object means "fit". Casting the type of a function changes what it accepts. It's dangerous to allow a function to accept whatever isn't what it originally accepts.

Consider this code:

class Base {};
class Derived : public Base {
    public:
    int t;
    void useDerived() {}
};

void useDerived(Derived *d){
    d->useDerived();
}

What should happen if a Base object is passed?

Base b;
((void(*)(Base*))useDerived) (&b);

Even worse, what if another derivation of Base is passed?

class AnotherDerived : public Base {
    public:
    double t;
    void useDerived() {}
};
AnotherDerived ad;
((void(*)(Base*))useDerived) (&ad);

Upvotes: 1

seldon
seldon

Reputation: 510

Yes, but you're trying to do it the other way around. You cannot do

void takeDerived(Derived *c) { }

...

Base b;
takeDerived(&b);

The function pointer cast you're trying to do would enable these shenanigans; you could do

void (*ptr)(Base*) = takeDerived;
Base b;
ptr(&b); // Oops.

Then things would explode, and that would be bad.

Upvotes: 0

Related Questions