C ++继承和成员函数指针 [英] C++ inheritance and member function pointers

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

问题描述

在C ++中,成员函数指针可以用于指向派生(甚至是基类)类成员?



编辑:
也许一个例子会有帮助。假设我们有三个类的层次结构 X Y Z 按继承顺序。
Y 因此有一个基类 X 和一个派生类 Z



现在我们可以为类 p > Y 。这写为:

  void(Y :: * p)(); 

(为简单起见,我假设我们只对签名 void f()



现在可以使用此指针 p 指向 Y 的成员函数。



这个问题(两个问题真的) p>


  1. 可以 p 用于指向派生类中的函数 Z

  2. 可以 p 用于指向基类中的函数 X


解决方案std,§4.112成员的指针转换


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



52)指针转换为成员的规则(从指针到基础成员到派生的成员)与指向对象的指针的规则(从指针到派生指针到指针到基准)出现倒置(4.10,第10节)。这种反演对于确保类型安全是必要的。注意,指向成员的指针不是指向对象的指针或指向函数的指针,并且这种指针的转换规则不适用于指向成员的指针。特别是,指向成员的指针不能转换为void *。


简而言之,您可以将指针转换为一个可访问的非虚拟基类到指向派生类的成员的指针,只要成员不含糊。

  class A {
public:
void foo
};
class B:public A {};
class C {
public:
void bar();
};
class D {
public:
void baz();
};
class E:public A,public B,private C,public virtual D {
public:
typedef void(E :: * member)();
};
class F:public E {
public:
void bam();
};
...
int main(){
E :: member mbr;
mbr =& A :: foo; // invalid:ambiguous; E的A或B的A?
mbr =& C :: bar; // invalid:C is private
mbr =& D :: baz; // invalid:D is virtual
mbr =& F :: bam; // invalid:转换未由标准定义
...

转换另一个方向(通过 static_cast )由§5.2.9 9:


可以将类型为cv1T的D的成员的类型指针的值转换为类型指向类型为cv2T的B的成员的指针的右值,其中B是一个基类( 10类如果从指向T类型的B的成员的指针到到T类型的D的成员的指针的有效标准转换存在(4.11 conv.mem )和 cv2 是与cv1 相同的cv-qualification或更高的cv-qualification。 11)空成员指针值(4.11 conv.mem )转换为空成员指针值目标类型。如果B类包含原始成员,或者是包含原始成员的类的基类或派生类,则指向成员的结果指针指向原始成员。否则,转换的结果是未定义的。 [注意:虽然类B不需要包含原始成员,但是取消引用成员的指针的对象的动态类型必须包含原始成员;请参见 5.5 expr.mptr。 ]



11)函数类型(包括在指向成员函数
类型的指针中使用的类型) cv限定;请参阅
8.3.5 dcl.fct


简而言之,您可以从派生的 D :: * 到基本 B :: * ,如果你可以从 B :: * 转换为 D :: * ,但只能在类型为D的对象上使用 B :: * D.


In C++, can member function pointers be used to point to derived (or even base) class members?

EDIT: Perhaps an example will help. Suppose we have a hierarchy of three classes X, Y, Z in order of inheritance. Y therefore has a base class X and a derived class Z.

Now we can define a member function pointer p for class Y. This is written as:

void (Y::*p)();

(For simplicity, I'll assume we're only interested in functions with the signature void f() )

This pointer p can now be used to point to member functions of class Y.

This question (two questions, really) is then:

  1. Can p be used to point to a function in the derived class Z?
  2. Can p be used to point to a function in the base class X?

解决方案

C++03 std, §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)

52)The rule for conversion of pointers to members (from pointer to member of base to pointer to member of derived) appears inverted compared to the rule for pointers to objects (from pointer to derived to pointer to base) (4.10, clause 10). This inversion is necessary to ensure type safety. Note that a pointer to member is not a pointer to object or a pointer to function and the rules for conversions of such pointers do not apply to pointers to members. In particular, a pointer to member cannot be converted to a void*.

In short, you can convert a pointer to a member of an accessible, non-virtual base class to a pointer to a member of a derived class as long as the member isn't ambiguous.

class A {
public: 
    void foo();
};
class B : public A {};
class C {
public:
    void bar();
};
class D {
public:
    void baz();
};
class E : public A, public B, private C, public virtual D {
public: 
    typedef void (E::*member)();
};
class F:public E {
public:
    void bam();
};
...
int main() {
   E::member mbr;
   mbr = &A::foo; // invalid: ambiguous; E's A or B's A?
   mbr = &C::bar; // invalid: C is private 
   mbr = &D::baz; // invalid: D is virtual
   mbr = &F::bam; // invalid: conversion isn't defined by the standard
   ...

Conversion in the other direction (via static_cast) is governed by § 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 class.derived) 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 conv.mem), and cv2 is the same cv-qualification as, or greater cv-qualification than, cv1.11) The null member pointer value (4.11 conv.mem) 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 expr.mptr.oper.]

11) Function types (including those used in pointer to member function types) are never cv-qualified; see 8.3.5 dcl.fct.

In short, you can convert from a derived D::* to a base B::* if you can convert from a B::* to a D::*, though you can only use the B::* on objects that are of type D or are descended from D.

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

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