【问题标题】:Using base class function pointer to access derived class member function使用基类函数指针访问派生类成员函数
【发布时间】:2013-04-12 12:06:51
【问题描述】:

我在我的项目中使用函数指针,遇到问题,创建了一个测试用例来显示它......下面的代码在 MSVC2005 上失败并出现以下错误(简单来说,我想通过基类函数指针访问派生类函数)

错误 C2440: '=' : 无法从 'void (__thiscall ClassB::* )(void)' 到 'ClassAFoo'

class ClassA {
 public: 
    virtual void foo() 
    {
       printf("Foo Parent"); 
    }
};

typedef void (ClassA::*ClassAFoo)();

class ClassB : public ClassA {
 public:
    virtual void foo() 
    { 
        printf("Foo Derived"); 
    }
};

int main() {
    ClassAFoo fPtr;
    fPtr = &ClassB::foo;
}

我的问题是

  1. 我无法通过基类函数指针访问派生类函数是 C++ 行为还是它的编译器错误?
  2. 我一直在玩上面的案例,如果我注释掉ClassB::foo,这段代码编译正常,无需进一步修改,为什么会这样,fPtr = &ClassB::foo;不应该再次导致编译时错误吗?

【问题讨论】:

标签: c++ visual-c++ visual-studio-2005


【解决方案1】:
  1. 这是正确的行为。可以这样想:ClassB 的所有实例都有成员 ClassA::foo,但并非所有 ClassA 的实例都有成员 ClassB::foo;只有那些实际上是ClassB 实例的基类子对象的ClassA 实例才有它。因此,将ClassB::foo 分配给ClassAFoo,然后将ClassAFoo 与“纯”ClassA 对象结合使用会尝试调用不存在的函数。

  2. 如果你把fooClassB中去掉,表达式ClassB::foo实际上指的是ClassA::foo,它继承于ClassB,所以没有问题。

详细说明 1. 进一步:指向成员的指针实际上与普通指针的工作方式相反。使用普通指针,您可以将ClassB* 分配给ClassA*(因为ClassB 的所有实例也是ClassA 的实例),但反之则不然。使用成员指针,您可以将ClassA::* 分配给ClassB::*(因为ClassB 包含ClassA 的所有成员),反之则不行。

【讨论】:

    【解决方案2】:

    是的,没关系。您不能分配给class A 的函数指针class B 的函数指针。 你可以这样做

    fPtr = &ClassA::foo;
    ClassB b;
    classA* a = &b;
    (a->*fPtr)();
    

    并在ClassB 函数中被覆盖。

    ClassB 中没有函数foo 时,将使用ClassA 的函数。 Live example

    【讨论】:

      【解决方案3】:

      首先,我不是 C++ 专家(我正在努力学习 C++)。如果我错了,请纠正我,这是一个实验。

      作为学习成员函数指针的一部分,我还在搜索代码示例以使用基成员函数指针调用派生成员。通过这个线程后,我创建了一个代码示例,即使成员函数不是虚拟的,它也能够调用派生成员函数。

      我正在使用 Delegator 来充当 Invoker。我希望它可能对某人有所帮助。 (如果我做错了什么,请纠正我)

      class AbstractBase
      {
      protected:
          AbstractBase()
          {};
      
          virtual ~AbstractBase()
          {};
      
      public:
          //Place holder method
          void SimpleMethod(void)
          {
              printf_s("\nAbstractBase::SimpleMethod");
          };
      };
      
      class Derived : public AbstractBase
      {
      public:
          //This overridden but not virtual.
          void SimpleMethod(void)
          {
              printf_s("Derived::SimpleMethod");
          };
      };
      
      typedef void (AbstractBase::*SimpleMethodCallback)();
      
      class Delegator
      {
      private:
          AbstractBase * pbasePtr;
          SimpleMethodCallback pCallback;
      
      public:
          Delegator()
          {
              this->pbasePtr = nullptr;
              this->pCallback = nullptr;
          };
      
          void RegisterCallback(AbstractBase * pbasePtr, SimpleMethodCallback callback)
          {
              if (pbasePtr == nullptr || callback == nullptr)
                  throw "Delegate target or callback cannot be null";
      
              this->pbasePtr = pbasePtr;
              this->pCallback = callback;
          };
      
          void Invoke()
          {
              if (this->pbasePtr == nullptr || this->pCallback == nullptr)
                  throw "Inoke cannot be performed on null target or callback";
              (pbasePtr->*pCallback)();
          }
      };
      
      
      int _tmain(int argc, _TCHAR* argv[])
      {
          Delegator delegate;
          delegate.RegisterCallback(new Derived(), reinterpret_cast<SimpleMethodCallback>(&Derived::SimpleMethod));
      
          delegate.Invoke();
      
          return 0;
      }
      

      输出:

      delegate.Invoke() 将调用 Derived::SimpleMethod() 并且输出将是“Derived::SimpleMethod”**

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-03-25
        • 2021-08-05
        • 1970-01-01
        • 2011-08-23
        • 2011-01-27
        • 2015-02-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多