向下转换指向成员的指针会导致未定义的行为
我在某处读到,指向派生类成员的指针可以转换为指向其基类成员的指针。当我读到这篇文章时,我聪明的头脑开始思考许多例子,并不断发明无限多种可能性:这样的强制转换是否会导致未定义的行为?
“指向 cv1 T 类型的 D 成员的指针”类型的纯右值可以是 转换为“指向 cv2 T 类型的 B 成员的指针”类型的纯右值, 其中 D 是完整的类类型,B 是 D 的基类,如果 cv2 是 与 cv1 具有相同的简历资格或更高的简历资格。 [..] 否则,行为未定义。
[注6:虽然B类不需要包含原始成员,但通过指向成员的指针进行间接访问的对象的动态类型必须包含原始成员;参见[expr.mptr.oper]。 ——尾注]。
我想知道,以下强制转换是否会导致 UB 因为它们不是从 D
的“指向成员的指针”强制转换为“指向成员的指针” ” B
struct B { int a; void f(); };
struct D1:B {};
struct D2:B {};
static_cast<int D1::*>(&B::a); // UB? (#1)
static_cast<int D2::*>(&B::a); // UB? (#2)
static_cast<void (D1::*)()>(&B::f); // UB? (#3)
static_cast<void (D2::*)()>(&B::f); // UB? (#4)
int B::*b1 = &D1::a;
int B::*b2 = &D2::a;
static_cast<int D1::*>(b1); // OK? (#5) -- fix of (#1)
static_cast<int D2::*>(b2); // OK? (#6) -- fix of (#2)
void (B::*f1)() = &D1::f;
void (B::*f2)() = &D2::f;
static_cast<void (D1::*)()>(f1); // OK? (#7) -- fix of (#3)
static_cast<void (D2::*)()>(f2); // OK? (#8) -- fix of (#4)
static_cast<int D2::*>(b1); // UB? (#9)
static_cast<int D1::*>(b2); // UB? (#10)
static_cast<void (D2::*)()>(f1); // UB? (#11)
static_cast<void (D1::*)()>(f2); // UB? (#12)
给定这个成员访问表达式E1.*E2,如果E1的动态类型 不包含 E2 引用的成员,行为是 未定义。
struct B { };
struct D : B { int b; void g(); };
B* b = new B;
(b->*static_cast<void(B::*)()>(&D::g))(); // UB? (#13)
b->*static_cast<int B::*>(&D::b); // UB? (#14)
B *b = new D;
(static_cast<D*>(b)->*(&D::g))(); // OK? (#16) -- fix of (#13)
static_cast<D*>(b)->*(&D::b); // OK? (#17) -- fix of (#14)
I read somewhere that a pointer-to-member of a derived class can be converted to pointer-to-member of its base class. When I have read this, my smart mind started to think of many examples and keep inventing an infinite number of possibilities: do such casts lead to undefined behavior?.
A prvalue of type “pointer to member of D of type cv1 T” can be
converted to a prvalue of type “pointer to member of B of type cv2 T”,
where D is a complete class type and B is a base class of D, if cv2 is
the same cv-qualification as, or greater cv-qualification than, cv1. [..] Otherwise, the behavior is undefined.[Note 6: Although class B need not contain the original member, the dynamic type of the object with which indirection through the pointer to member is performed must contain the original member; see [expr.mptr.oper]. — end note].
I want to know, are the following casts leads to UB or not since they are not cast from "pointer-to-member" of D
to "pointer-to-member" of B
struct B { int a; void f(); };
struct D1:B {};
struct D2:B {};
static_cast<int D1::*>(&B::a); // UB? (#1)
static_cast<int D2::*>(&B::a); // UB? (#2)
static_cast<void (D1::*)()>(&B::f); // UB? (#3)
static_cast<void (D2::*)()>(&B::f); // UB? (#4)
int B::*b1 = &D1::a;
int B::*b2 = &D2::a;
static_cast<int D1::*>(b1); // OK? (#5) -- fix of (#1)
static_cast<int D2::*>(b2); // OK? (#6) -- fix of (#2)
void (B::*f1)() = &D1::f;
void (B::*f2)() = &D2::f;
static_cast<void (D1::*)()>(f1); // OK? (#7) -- fix of (#3)
static_cast<void (D2::*)()>(f2); // OK? (#8) -- fix of (#4)
static_cast<int D2::*>(b1); // UB? (#9)
static_cast<int D1::*>(b2); // UB? (#10)
static_cast<void (D2::*)()>(f1); // UB? (#11)
static_cast<void (D1::*)()>(f2); // UB? (#12)
Given this member access expression E1.*E2, If the dynamic type of E1
does not contain the member to which E2 refers, the behavior is
undefined.
struct B { };
struct D : B { int b; void g(); };
B* b = new B;
(b->*static_cast<void(B::*)()>(&D::g))(); // UB? (#13)
b->*static_cast<int B::*>(&D::b); // UB? (#14)
B *b = new D;
(static_cast<D*>(b)->*(&D::g))(); // OK? (#16) -- fix of (#13)
static_cast<D*>(b)->*(&D::b); // OK? (#17) -- fix of (#14)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
第一个代码段中的
#1
到#12
都不是 UB,因为它们只是将指向成员的指针从基类转换为派生类。这是隐式转换,甚至不需要显式static_cast
。转换在 [conv.mem] 中描述。您对标准的引用不适用,因为 [expr.static.cast]/4 已经涵盖了隐式转换序列。由于您引用的原因,
#13
和#14
是 UB,因为您创建的B
对象是最派生的对象,并且它不' t 包含引用的成员。#16
和#17
看起来不错。static_cast
将产生一个指向D
对象的指针,因为b
指向一个B
对象,该对象是D
对象的基础子对象。None of
#1
through#12
in the first snippet are UB, since they are just casting a pointer-to-member from base class to derived class. This is an implicit conversion and the explicitstatic_cast
wouldn't even be required. The conversion is described in [conv.mem]. Your quote from the standard doesn't apply, since [expr.static.cast]/4 already covers implicit conversion sequences.#13
and#14
are UB for the reason you quoted, because theB
object you created is the most-derived object and it doesn't contain the referenced member.#16
and#17
look ok. Thestatic_cast
will result in a pointer to aD
object, sinceb
points to aB
object which is a base subobject of aD
object.