3

我在我的项目中使用函数指针,面临问题,创建了一个测试用例来显示它......下面的代码在 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;再次导致编译时错误?
4

3 回答 3

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

  2. 如果从 中删除fooClassB表达式实际上是ClassB::foo指在ClassA::foo中继承的ClassB,所以那里没有问题。

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

于 2013-04-12T12:14:56.383 回答
3

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

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

并且ClassB将调用函数中的覆盖。

当 中没有函数fooClassBClassA将使用 of 函数。活生生的例子

于 2013-04-12T12:14:50.013 回答
0

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

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

我正在使用委托人充当调用者。我希望它可能对某人有所帮助。(纠正我如果我做错了什么)

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”**

于 2017-12-21T07:51:39.330 回答