“upcast”方法指针并将其与基类指针一起使用是否安全?

时间:2010-11-25 01:04:20

标签: c++ polymorphism member-function-pointers

假设我有一个指针类型可以保存基类方法的地址。我可以为其分配子类方法的地址并期望它正常工作吗?在我的情况下,我使用它与基类指针,对象的动态类型是派生类。

struct B
{
    typedef void (B::*MethodPtr)();
};

struct D: public B
{
    void foo() { cout<<"foo"<<endl; }
};

int main(int argc, char* argv[])
{
    D d;
    B* pb = &d;

    //is the following ok, or undefined behavior?
    B::MethodPtr mp = static_cast<B::MethodPtr>(&D::foo);
    (pb->*mp)();
}

标准在讨论static_cast时说了这个:

5.2.9.9 类型“指向cv1 T类型D的成员的指针”的右值可以转换为类型为“指向cv2 T类型B的成员的指针”的右值,其中B是D的基类(第10节),如果存在从“指向类型T的B的成员的指针”到“指向类型T的D的成员的指针”的有效标准转换(4.11),并且cv2是相同的 cv-qualification为,或者比cv1更高的cv资格。 63)空成员指针值(4.11)被转换为目标类型的空成员指针值。如果类B包含原始成员,或者是包含原始成员的类的基类或派生类,则指向成员的结果指针指向原始成员。否则,演员的结果是不确定的。 [注意:虽然B级需要 不包含原始成员,取消引用成员指针的对象的动态类型必须包含原始成员;见5.5。]

与往常一样,我很难破译标准。它有点说没关系,但我不能100%确定上述文本是否真的适用于我的示例代码中的情况。

1 个答案:

答案 0 :(得分:9)

这是有效的。

  

如果B类包含原始成员,

B不包含D :: Foo,所以没有。

  

或是包含原始成员的类的基础[...]

B是D的基础,所以这就成立了。结果:

  

指向成员的结果指针指向原始成员

条款5.2.9 9表示只有在你也可以向下转换时才可以向上转换,如第4.11节所述:

  

类型“指向cv T类型B的成员的指针”的rvalue,其中B是类类型,可以转换为类型为“指向cv T类型的D的成员的指针”的右值,其中D是a B的派生类(第10节)如果B是不可访问的(第11条),D的模糊(10.2)或虚拟(10.1)基类,则需要进行此转换的程序是不正确的。

这只是说只要B可以访问,你就可以向下转换,不是虚拟的,只在D的继承图中出现一次。

upcasting方法指针固有的危险是你可以在实际类型为B的对象上调用mp。只要处理D :: *的代码块也处理D *,你就可以避免这种情况。