将派生虚拟覆盖转换为基础纯虚拟成员
Cast derived virtual override to base pure virtual member
我理解为什么您不能简单地将派生的 class 成员函数指针转换为基础 class 成员函数指针,如 here 所述。
但是,给出这个片段:
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
)?我明白为什么我不能用普通函数来做这个,但是恕我直言,如果是纯虚函数,编译器保证它会被实现(如果它没有完成,我会得到一个关于 class 的错误B
与演员无关)。
即使保证它已实现,它也可能使用仅在 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 中的哪一个的信息,因为该信息已被丢弃。为了避免这种歧义,不允许使用这种向上转换。
无需操纵 &derived::foo
的类型。可以只使用 &base::foo
代替。
指向成员函数的指针尊重虚拟性。这个电话
base* pBase = new derived;
auto pFoo = &base::foo;
(pBase->*pFoo)();
实际上会调用 derived::foo
,就像简单的调用 pBase->foo()
一样。
我理解为什么您不能简单地将派生的 class 成员函数指针转换为基础 class 成员函数指针,如 here 所述。
但是,给出这个片段:
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
)?我明白为什么我不能用普通函数来做这个,但是恕我直言,如果是纯虚函数,编译器保证它会被实现(如果它没有完成,我会得到一个关于 class 的错误B
与演员无关)。
即使保证它已实现,它也可能使用仅在 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 中的哪一个的信息,因为该信息已被丢弃。为了避免这种歧义,不允许使用这种向上转换。
无需操纵 &derived::foo
的类型。可以只使用 &base::foo
代替。
指向成员函数的指针尊重虚拟性。这个电话
base* pBase = new derived;
auto pFoo = &base::foo;
(pBase->*pFoo)();
实际上会调用 derived::foo
,就像简单的调用 pBase->foo()
一样。