通过基 class 函数指针调用派生 class

Calling derived class through base class function pointer

我可以通过基 class 函数 pointer 调用派生的 class 吗?

我知道我的示例 有效 ,但是否保证始终如此(假设对象实际实现了该功能!),或者这只是编译器的特性我在用?

按照这种逻辑,不能简单地从 "CBase" 中导出所有 classes(在本例中是空的,所以我猜没有开销)并忽略函数指针中的类型吗?

#include <iostream>

struct CBase
{ 
};

struct CDerived : CBase
{
    void MyFunction()
    {
        std::cout << "Called OK" << std::endl;
    }
};

typedef void (CBase::*FunctionPointer)();


int main()
{
    CDerived* base = new CDerived();

    FunctionPointer pointer = static_cast<FunctionPointer>(&CDerived::MyFunction);
    (base->*pointer)();

    delete base;
}

示例使用场景: 派生的 class 接受一个或多个指向基 class 中的 "callbacks" 的指针。是否可以仅使用派生的 class 定义回调类型,从而放弃对模板的需求?

您可以使用此方法,但转换指针根本不是一个好的做法。您使用的方法与多态性没有共同之处。更好的实现方法是使用 virtual 函数和 pure 函数。

你的基础 class 必须有一个纯函数(纯函数也是虚拟的)并且你的派生 class 必须实现这个函数。因此,您将能够使用基指针调用此函数,并调用派生 class 的实现。

#include "stdafx.h"
#include <iostream>

struct CBase
{
    virtual void MyFunction() =0;    // this is a `pure` function. Pure means it's a virtual and may not have implementation. If a class has at least one pure function it means this class is an abstract class
    virtual ~CBase()=default;       //  gotta be or we will have a memory leak during `delete`..
};

struct CDerived : CBase
{
    virtual void MyFunction() override
    {
        std::cout << "Called OK" << std::endl;
    }
};

//typedef void (CBase::*FunctionPointer)();


int main()
{
    CBase* base = new CDerived();

    base->MyFunction();

    delete base;

    system("pause");

    return 0;
}

是的,保证有效。来自 [expr.static.cast]:

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 B is a base class (Clause 10) of D, if cv2 is the same cv-qualification as, or greater cv-qualification than, cv1.70 If no valid standard conversion from “pointer to member of B of type T” to “pointer to member of D of type T” exists (4.11), the program is ill-formed. 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.

在这种情况下,我们将指向类型 void()CDerived 成员的指针转换为指向类型 void()CBase 成员的指针。 CBase 是包含原始成员的 class 的基础,因此生成的指针指向原始成员。

来自[expr.mptr.oper]:

Abbreviating pm-expression.*cast-expression as E1.*E2, E1 is called the object expression. If the dynamic type of E1 does not contain the member to which E2 refers, the behavior is undefined.

在这种情况下,pointer 指向原始成员。 base 有那个成员。所以这很好。


请注意,在您的示例中,base 实际上是 CDerived*。写成同样有效:

CDerived d;
CBase* b = &d;

(b->*pointer)(); // ok - the dynamic type of b contains the member to which pointer refers