“上传”是安全的一个方法指针并使用它与基类指针? [英] Is it safe to "upcast" a method pointer and use it with base class pointer?

查看:99
本文介绍了“上传”是安全的一个方法指针并使用它与基类指针?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  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;

//是下面的ok,还是未定义的行为?
B :: MethodPtr mp = static_cast< B :: MethodPtr>(& D :: foo);
(pb-> * mp)();
}

标准在谈论static_cast时说:

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

和往常一样,我有这么难的时间来解读标准。它有点说,这是确定,但我不是100%确定上述文本是否真的适用于我的示例代码中的情况。

解决方案<


如果B类包含原始成员,


B不包含D :: Foo,因此没有。


[...]包含原始成员的类


B是D的基数,因此:


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


条款5.2.9 9说如果你也可以按照第4.11节中的规定进行向下转换:


类型指向类型cv T的B的成员的指针的右值,其中B是类类型,可以被转换为类型指向类型cv T的D的成员的指针的右值,其中D是如果B是不可访问的(第11条),D的歧义(10.2)或虚拟(10.1)基类,一个需要这种转换的程序是不成立的。


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



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


Let's say I have a pointer type that can hold the address of a base class method. Can I assign the address of a subclass method to it and expect it to work correctly? In my case I'm using it with a base class pointer and the dynamic type of the object is the derived class.

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

The standard says this when talking about static_cast:

5.2.9.9 An rvalue of type "pointer to member of D of type cv1 T" can be converted to an rvalue of type "pointer to member of B of type cv2 T", where B is a base class (clause 10) of D, if a valid standard conversion from "pointer to member of B of type T" to "pointer to member of D of type T" exists (4.11), and cv2 is the same cv-qualification as, or greater cv-qualification than, cv1. 63) The null member pointer value (4.11) is converted to the null member pointer value of the destination type. If class B contains the original member, or is a base or derived class of the class containing the original member, the resulting pointer to member points to the original member. Otherwise, the result of the cast is undefined. [Note: although class B need not contain the original member, the dynamic type of the object on which the pointer to member is dereferenced must contain the original member; see 5.5.]

As always, I'm having such a hard time deciphering the standard. It kinda says that it is ok, but I'm not 100% sure if the above text really applies to the situation in my example code.

解决方案

It's valid.

If class B contains the original member,

B doesn't contain D::Foo, so no.

or is a base [...] of the class containing the original member

B is a base of D, so this holds. As a result:

the resulting pointer to member points to the original member

Clause 5.2.9 9 says you can upcast only if you can also downcast, as specified in § 4.11:

An rvalue of type "pointer to member of B of type cv T," where B is a class type, can be converted to an rvalue of type "pointer to member of D of type cv T," where D is a derived class (clause 10) of B. If B is an inaccessible (clause 11), ambiguous (10.2) or virtual (10.1) base class of D, a program that necessitates this conversion is ill-formed.

This just says you can downcast as long as B is accessible, isn't virtual and only appears once in D's inheritance diagram.

The danger inherent in upcasting method pointers is that you could call mp on an object whose actual type is B. As long as a code block that deals with D::* also deals with D*, you can avoid this.

这篇关于“上传”是安全的一个方法指针并使用它与基类指针?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆