“向上转型"是否安全?方法指针并将其与基类指针一起使用?
假设我有一个指针类型,它可以保存基类方法的地址.我可以将子类方法的地址分配给它并期望它正常工作吗?在我的例子中,我将它与基类指针一起使用,对象的动态类型是派生类.
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)();
}
标准在谈到 static_cast 时这样说:
The standard says this when talking about 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-qualification.63)将空成员指针值(4.11)转换为目标类型的空成员指针值.如果类 B 包含原始成员,或者是包含原始成员的类的基类或派生类,则指向成员的结果指针指向原始成员.否则,强制转换的结果是未定义的.[注:虽然B类需要不包含原始成员,取消引用指向成员的指针的对象的动态类型必须包含原始成员;见 5.5.]
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.]
与往常一样,我很难破译标准.它有点说没关系,但我不能 100% 确定上述文本是否真的适用于我的示例代码中的情况.
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.
推荐答案
有效.
如果类 B 包含原始成员,
If class B contains the original member,
B 不包含 D::Foo,所以没有.
B doesn't contain D::Foo, so no.
or 是包含原始成员的类的基 [...]
or is a base [...] of the class containing the original member
B 是 D 的底,所以这成立.结果:
B is a base of D, so this holds. As a result:
指向成员的结果指针指向原始成员
the resulting pointer to member points to the original member
第 5.2.9 条第 9 条规定,只有当您也可以向下转换时,您才能向上转换,如 § 4.11 中所述:
Clause 5.2.9 9 says you can upcast only if you can also downcast, as specified in § 4.11:
指向类型为 cv T 的 B 成员的指针"类型的右值,其中 B 是类类型,可以转换为类型为指向类型为 cv T 的 D 成员的指针"类型的右值,其中 D 是B 的派生类(第 10 条).如果 B 是 D 的不可访问(第 11 条)、模棱两可 (10.2) 或虚拟 (10.1) 基类,则需要这种转换的程序是不正确的.
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.
这只是说只要 B 是可访问的,不是虚拟的并且只在 D 的继承图中出现一次,就可以向下转换.
This just says you can downcast as long as B is accessible, isn't virtual and only appears once in D's inheritance diagram.
向上转换方法指针所固有的危险在于,您可以在实际类型为 B 的对象上调用 mp
.只要处理 D::* 的代码块也处理 D*,你可以避免这种情况.
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.
相关文章