将派生的虚拟重写强制转换为基纯虚拟成员

Cast derived virtual override to base pure virtual member

本文关键字:转换 虚拟成员 派生 虚拟 重写      更新时间:2023-10-16

我理解为什么不能像这里解释的那样,简单地将派生类成员函数指针强制转换为基类成员函数指针。

但是,给定这个片段:

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));

我想问,是否可以修饰基函数签名,以便编译器理解它是一个纯虚拟方法,并且它将在层次结构中的某个地方实现(否则我无法构造B类型的对象)?我理解为什么我不能用普通函数做到这一点,但IMHO在纯虚拟函数的情况下,编译器有保证它会被实现(如果没有实现,我会得到关于类B的错误,而不是关于强制转换的错误)。

不需要操作&derived::foo的类型。可以直接使用&base::foo

指向成员函数的指针尊重虚拟性。此呼叫

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

将实际调用derived::foo,就像简单调用pBase->foo()一样。

即使有实现的保证,它也可能使用仅在derived中声明的其他数据成员。一个可能的解决方案是使用函数指针并将this作为第一个参数传递(这也说明了为什么不能通过virtual执行此操作)。

考虑以下菱形层次结构:

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;
};

现在考虑一个场景,其中允许从Derived::*向base::*进行上转换。应该调用哪个函数?编译器将丢失有关您希望调用D1::foo、D2::foo或Derived::foo中哪一个的信息,因为这些信息已被丢弃。为了避免这种模棱两可的情况,不允许进行这种升级。