成员转换指针 [英] Pointer to member conversion

查看:121
本文介绍了成员转换指针的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



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

strong>


类型为指向类型为cv T的B的成员的指针的右值,其中B是类类型,可以转换如果B是不可访问的(第11条),则模糊(10.2)或虚拟(10.1)基本上是不可访问的(第11条),其中D是类型为cv T的D的成员的指针的右值D类,需要这种转换的程序是错误的。转换的结果是指在转换发生之前与指向成员的指针相同的成员,但它引用基类成员,就像它是
派生类的成员一样。结果引用了B的D实例中的成员。由于结果具有类型指向类型cv T的D的成员的指针,所以它可以用D对象来解引用。结果与如果用B的B子对象来取消引用B的成员的指针一样。空成员指针值被转换为目的地类型的空成员指针值。52)


5.2.9 / 9 static_cast


类型指向类型cv1 T的D的成员的指针的值可以被转换为类型指向类型cv2 T的B的成员的指针的右值,其中B是D的基本类(子句10)如果存在从指向T类型的B的成员的指针到到类型T的D的成员的指针的有效标准转换(4.11),并且cv2与cv1具有相同的cv限定条件或更大的cv限定条件.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?

在5.2.9 / 9的注释中,它还说,虽然类B不需要包含原始成员,取消引用成员的指针的对象的动态类型必须包含原始成员。



我对该段落的措辞感到困惑。上面的代码是否有效?



我搜索了该网站,还有一个类似的问题, c ++继承和成员函数指针,其答案仅涵盖从指针到基类的成员转换为指向派生类的成员的指针的情况。

解决方案

您写的代码是完全有效的。没有什么问题(除了 Derived :: a 是私有的)的事实。它是良好形式和行为被定义(到目前为止)。正如标准的引用部分所说,使用显式的 static_cast ,upcast成员指针是完全合法的,这正是你在做什么。 5.2.9 / 9从来没有说尖端的成员必须出现在基类中。



另外,正如你从标准中引用的,在指针的取消引用时需要在对象中的成员,而不是在初始化时。这当然取决于在成员访问运算符( - > * 的左侧使用的对象的动态类型) 。* )。该类型只在运行时才知道,因此不能由编译器检查。



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


4如果对象
的动态类型不包含指针引用的
的成员,行为是
undefined 。


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

  Base b; 
b。* pa; // 1

派生d;
d。* pa; // 2

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

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


I just found the following paragraphs in c++03 standard draft relevant to pointer to member conversion.

4.11/2 Pointer to member conversions

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. The result of the conversion refers to the same member as the pointer to member before the conversion took place, but it refers to the base class member as if it were a member of the derived class. The result refers to the member in D’s instance of B. Since the result has type "pointer to member of D of type cv T," it can be dereferenced with a D object. The result is the same as if the pointer to member of B were dereferenced with the B sub-object of D. The null member pointer value is converted to the null member pointer value of the destination type.52)

5.2.9/9 static_cast

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. ]

So here's my question. As 5.2.9/9 says, a pointer to member of D can be converted to a pointer to member of B, if there's a valid conversion described in 4.11/2 exists. Do this mean that if there's a member 'm' of D which is not inherited from B, the pointer to member 'm' cannot be casted to the type of pointer to member of 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 ?

In the note of 5.2.9/9, it also says that 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.

I get confused with the wording of the paragraph. Is the code above valid ?

I searched the site, and there's a similar question, c++ inheritance and member function pointers, whose answer only covered the case that conversion from pointer to member of base class to pointer to member of derived class.

解决方案

The code you wrote is perfectly valid. There's nothing wrong with it (aside from the fact that Derived::a is private). It is well-formed and the behavior is defined (so far). As the quoted portion of the standard says, it is perfectly legal to upcast member pointers using an explicit static_cast, which is exactly what you are doing. 5.2.9/9 never says that the pointed member has to be present in the base class.

Also, as you correctly quoted from the standard, the presence of the actual member in the object is required later at the moment of dereference of the pointer, not at the moment of initialization. This, of course, depends on the dynamic type of the object used at the left-hand side of member-access operator (->* or .*). The type is only known at run-time and thus cannot be checked by the compiler.

This requirement is included as a mere note into 5.2.9/9, but it is reiterated in a more formal form in 5.5/4

4 If the dynamic type of the object does not contain the member to which the pointer refers, the behavior is undefined.

So, for example, in the context of your example the following lines of code are well-formed

Base b;
b.*pa; // 1

Derived d;
d.*pa; // 2

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

However, the first dereference produces undefined behavior (since object b does not contain the member), while both the second one and the third one are perfectly legal.

这篇关于成员转换指针的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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