Tim*_*imo 11 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)();
}
Run Code Online (Sandbox Code Playgroud)
在讨论static_cast时,标准说明了这一点:
5.2.9.9类型"指向Cv1 T类型D的成员的指针"的rvalue可以转换为类型为"指向cv2 T类型B的成员的指针"的rvalue,其中B是D的基类(第10节),如果a从"指向T类型B的成员的指针"到"指向T类型D的成员的指针"的有效标准转换存在(4.11),并且cv2与cv1具有相同的cv资格,或者更高的cv资格.63)空成员指针值(4.11)被转换为目标类型的空成员指针值.如果类B包含原始成员,或者是包含原始成员的类的基类或派生类,则指向成员的结果指针指向原始成员.否则,演员的结果是不确定的.[注意:虽然B类不需要包含原始成员,取消引用成员指针的对象的动态类型必须包含原始成员; 见5.5.]
和往常一样,我很难破译标准.它有点说没关系,但我不能100%确定上述文本是否真的适用于我的示例代码中的情况.
这是有效的.
如果B类包含原始成员,
B不包含D :: Foo,所以没有.
或者是包含原始成员的类的基础[...]
B是D的基础,所以这就成立了.结果是:
生成的指向成员的指针指向原始成员
第5.2.9条第9款规定,如果您也可以按照第4.11节的规定进行向下转换,则只能进行转发:
类型为"cv T类型的B成员的指针"的r值,其中B是类类型,可以转换为类型为"指向类型为cv T的D的成员的指针"的右值,其中D是派生类(如果B是不可访问的(第11条),D的模糊(10.2)或虚拟(10.1)基类,则需要这种转换的程序是不正确的.
这只是说只要B可以访问就可以向下转换,不是虚拟的,只在D的继承图中出现一次.
upcasting方法指针固有的危险是你可以调用mp一个实际类型为B的对象.只要处理D ::*的代码块也处理D*,你就可以避免这种情况.