【问题标题】:Calling derived class through base class function pointer通过基类函数指针调用派生类
【发布时间】:2016-10-06 08:05:18
【问题描述】:

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

我知道我的示例有效,但它是否保证总是这样做(假设对象实际上实现了该函数!),或者这只是我正在使用的编译器的特性?

通过这种逻辑,不能简单地从“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;
}

示例使用场景: 一个派生类,它采用一个或多个指向基类中“回调”的指针。是否可以只使用派生类定义回调类型,从而放弃对模板的需求?

【问题讨论】:

  • 为什么要这样做?
  • 以我有一个带有“回调”指针的派生类为例。我想知道我是否可以使用派生类来定义它并放弃对模板的需求。
  • 我试过了,it worked。我不知道它是否应该......
  • clean感到抱歉。我的意思是pure
  • 好的,multiple inheritance doesn't stump it either...我现在很感兴趣。好问题!

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


【解决方案1】:

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

类型为“指向 cv1 T 的成员的指针”类型的纯右值可以转换为“指针”类型的纯右值 到类型为 cv2 T”的B 的成员,其中BD 的基类(第 10 条),如果 cv2 相同cv-资格 为或大于 cv1.70 的 cv 限定 如果没有从“指向 B 的成员的指针”的有效标准转换 类型 T”到“指向类型 T 的 D 成员的指针”存在(4.11),程序是非良构的。空成员 指针值 (4.11) 被转换为目标类型的空成员指针值。如果类 B 包含 原始成员,或者是包含原始成员的类的基类或派生类,结果 指向成员的指针指向原始成员。

在这种情况下,我们将指向CDerived 类型void() 的成员的指针转换为指向CBase ov 类型void() 的成员的指针。 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

【讨论】:

    【解决方案2】:

    您可以使用此方法,但转换指针根本不是一个好习惯。您使用的方法与多态性没有任何共同之处。更好的实现方法是使用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;
    }
    

    【讨论】:

    • 这是否需要基类知道派生类包含的内容?以您有多个“处理程序”函数并且基类不知道有多少处理程序的情况为例。
    • “纯虚拟”是 C++ 程序员会知道的正确术语。
    • 这就是多态性创造的目的。所有基类只知道一个接口,但它对实现一无所知
    猜你喜欢
    • 2010-12-24
    • 1970-01-01
    • 2012-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-18
    • 1970-01-01
    • 2012-01-07
    相关资源
    最近更新 更多