Rudolfs Bundulis
Rudolfs Bundulis

Reputation: 11944

Cast derived virtual override to base pure virtual member

I understand why you cannot simply cast a derived class member function pointer to base class member function pointer as explained here.

But, given this snippet:

struct base
{
    virtual void foo() = 0;
};

struct derived : base
{
    void foo() override {};
};

struct invoker
{
    typedef void(base::*target)();

    invoker(base* b, target t)
    {
        (b->*t)();
    }
};

template<typename B, typename D>
void (B::*cast(void (D::*method)()))()
{
    return static_cast<void(B::*)()>(method);
}

derived d;
invoker bad(&d, &derived::foo); //C2664
invoker good(&d, cast<base>(&derived::foo));

I wanted to ask is it possible to decorate the base function signature so that compiler understands it is a pure virtual method and and it will be implemented somewhere across the hierarchy (otherwise I could not construct an object of type B)? I understand why I can't do this with normal functions, but IMHO in case of a pure virtual function the compiler has a guarantee it will be implemented (in case it was not done I would get an error about the class B not about the cast).

Upvotes: 0

Views: 1347

Answers (3)

n. m. could be an AI
n. m. could be an AI

Reputation: 119877

There's no need to manipulate the type of &derived::foo. One can just use &base::foo instead.

Pointers to member functions respect virtuality. This call

base* pBase = new derived;
auto pFoo = &base::foo;
(pBase->*pFoo)();

will actually call derived::foo, exactly like a simple call pBase->foo() would.

Upvotes: 2

Consider the following diamond hierarchy:

struct base {
virtual void foo() = 0;
};

struct D1 : public virtual base {
virtual void foo() override;
};

struct D2 : public virtual base {
virtual void foo() override;
};

struct Derived : public virtual D1, D2 {
virtual void foo() final;
};

Now consider a scenario where a upcast is allowed from Derived::* to base::* . Which function should be invoked? The compiler loses information about which of D1::foo, D2::foo or Derived::foo you wish to call since that information has been cast away. To avoid this sort of ambiguity such an upcast is disallowed.

Upvotes: 0

lorro
lorro

Reputation: 10880

Even if there's a guarantee that it's implemented, it might use additional data members declared only in derived. A possible solution is to use function pointers and pass this as the first parameter (this also shows you why you cannot do it via virtual).

Upvotes: 0

Related Questions