通过基类函数指针

时间:2016-06-06 16:08:40

标签: c++ polymorphism member-function-pointers

我可以通过基类函数指针调用派生类,如下例所示吗?

我理解我的示例正常工作,但是保证总是这样做(假设对象实际上实现了函数!),或者这只是编译器的特殊性我是使用

通过这种逻辑,人们可以简单地从" CBase"中获取所有类别。 (在这种情况下是空的,所以我猜没有开销)并忽略函数指针中的类型?

#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;
}

示例使用场景: 一个派生类,它带有一个或多个指向&#34;回调&#34;在基类中。可以使用派生类来定义回调类型,从而放弃对模板的需求吗?

2 个答案:

答案 0 :(得分:5)

是的,它保证可以正常工作。来自[expr.static.cast]:

  

“指向 cv1 D类型的T成员的类型的prvalue”可以转换为类型为“指针”的prvalue   对于 cv2 B类型的T成员,其中BD的基类(第10条),如果 cv2 cv - 资格相同   as,或更高的cv-qualification,cv1.70如果没有有效的标准转换,则“指向B成员的指针   类型T“to”指向类型T的D成员的指针“存在(4.11),程序格式错误。 null成员   指针值(4.11)被转换为目标类型的空成员指针值。如果类B包含   原始成员,或者是包含原始成员的类的基类或派生类,由此产生   指向成员的指针指向原始成员。

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

来自[expr.mptr.oper]:

  

缩写pm-expression。* cast-expression为E1.*E2E1称为对象表达式。如果动态   E1的类型不包含E2引用的成员,行为未定义。

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

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

CDerived d;
CBase* b = &d;

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

答案 1 :(得分:0)

你可以使用这种方法,但铸造指针根本不是一个好习惯。您使用的方法与多态无关。实现此目的的更好方法是使用virtual函数和pure函数。

您的基类必须具有纯函数(纯函数也是虚函数),派生类必须实现此函数。因此,您将能够使用基指针调用此函数,并将调用派生类的实现。

#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;
}