C++ 指向成员转换的指针

C++ 指向成员转换的指针,c++,standards,C++,Standards,我刚刚在c++03标准草案中找到了与成员转换指针相关的以下段落 4.11/2指向成员转换的指针 “指向cv T类型的B的成员的指针”类型的右值,其中B是类类型,可以转换为“指向cv T类型的D的成员的指针”类型的右值,其中D是B的派生类(第10条)。如果B是D的不可访问(第11条)、不明确(10.2)或虚拟(10.1)基类,需要进行此转换的程序格式不正确。转换的结果引用的成员与转换前指向成员的指针相同,但它引用的基类成员与 派生类。结果引用D的B实例中的成员。由于结果的类型为“指向cv T类型的

我刚刚在c++03标准草案中找到了与成员转换指针相关的以下段落

4.11/2指向成员转换的指针

“指向cv T类型的B的成员的指针”类型的右值,其中B是类类型,可以转换为“指向cv T类型的D的成员的指针”类型的右值,其中D是B的派生类(第10条)。如果B是D的不可访问(第11条)、不明确(10.2)或虚拟(10.1)基类,需要进行此转换的程序格式不正确。转换的结果引用的成员与转换前指向成员的指针相同,但它引用的基类成员与 派生类。结果引用D的B实例中的成员。由于结果的类型为“指向cv T类型的D的成员的指针”,因此可以使用D对象取消引用它。结果与指向B成员的指针与D的B子对象解除引用的结果相同。空成员指针值转换为目标类型的空成员指针值。52)

5.2.9/9静态播放

如果存在从“指向T型B成员的指针”到“指向T型D成员的指针”的有效标准转换(4.11),则“指向cv1 T型D成员的指针”类型的右值可以转换为“指向cv2 T型B成员的指针”类型的右值,其中B是D的基类(第10条),cv2的cv限定与cv1相同,或大于cv1.63)。空成员指针值(4.11)转换为目标类型的空成员指针值。如果类B包含原始成员,或者是包含原始成员的类的基类或派生类,则指向该成员的结果指针将指向原始成员。否则,强制转换的结果是未定义的。[注:尽管B类需要 不包含原始成员,对象的动态类型(指向成员的指针在其上被取消引用)必须包含原始成员;请参见5.5。]

这是我的问题。如5.2.9/9所述,如果存在4.11/2中所述的有效转换,则指向D成员的指针可以转换为指向B成员的指针。这是否意味着如果D的某个成员“m”不是从B继承的,则指向成员“m”的指针不能强制转换为指向B成员的指针类型

class Base { };
class Derived : public Base 
{
    int a;
};
typedef int Base::* BaseMemPtr;
BaseMemPtr pa = static_cast<BaseMemPtr>(&Derived::a); // invalid, as per 5.2.9/9 ?
类基{};
派生类:公共基
{
INTA;
};
typedef int Base::*BaseMemPtr;
BaseMemPtr pa=静态_转换(&派生::a);//无效,根据5.2.9/9?
在5.2.9/9的注释中,它还指出,尽管类B不需要包含原始成员,但指向成员的指针所引用的对象的动态类型必须包含原始成员

我对这一段的措辞感到困惑。上面的代码有效吗


我搜索了这个站点,发现了一个类似的问题,其答案只涉及从指向基类成员的指针到指向派生类成员的指针的转换。

您编写的代码完全有效。它没有什么问题(除了
Derived::a
是私有的这一事实)。它结构良好,并且行为已定义(到目前为止)。正如标准中引用的部分所说,使用显式的
静态转换向上转换成员指针是完全合法的,这正是您正在做的。5.2.9/9从来没有说过尖头成员必须出现在基类中

此外,正如您从标准中正确引用的那样,对象中实际成员的存在是稍后在指针取消引用时需要的,而不是在初始化时需要的。当然,这取决于成员访问操作符左侧使用的对象的动态类型(
->*
*
)。该类型仅在运行时已知,因此编译器无法检查

该要求仅作为注释包含在5.2.9/9中,但在5.5/4中以更正式的形式重申

4如果对象的动态类型 不包含要访问的成员 指针引用时,行为为 未定义

因此,例如,在您的示例上下文中,以下代码行格式良好

Base b;
b.*pa; // 1

Derived d;
d.*pa; // 2

Base *pb = &d;
pb->*pa; // 3

但是,第一次取消引用会产生未定义的行为(因为object
b
不包含成员),而第二次和第三次取消引用都是完全合法的。

将指向数据成员值的指针指定给指向成员函数变量的指针。否则,是的,“演员的结果是不确定的。”很好的回答。但是我忍不住要提到,
sizeof b.*pa
给出了定义的行为,尽管“取消引用”了一个不存在的成员。(因为C++中没有什么是简单的……-p)@ jyRangulyHuff:嗯,是的。在我的例子中,未定义行为的出现与表达式求值期间的指针取消引用过程有关,而在
sizeof
的例子中,参数从未求值。当我将指向派生类的函数成员的指针强制转换为第二个基类型时,VC发出C4407警告,所以根据标准和你的回答,它不是符合标准的,对吗?@Alex.Shen:什么是“第二基类型”?“第二”是什么意思?你们有多个基类吗?@AndreyT:是的,我写了另一个测试,其中派生类有两个空基类。g++编译时没有警告。