【问题标题】: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;
}
我的问题是
- 我无法通过基类函数指针访问派生类函数是 C++ 行为还是它的编译器错误?
- 我一直在玩上面的案例,如果我注释掉
ClassB::foo,这段代码编译正常,无需进一步修改,为什么会这样,fPtr = &ClassB::foo;不应该再次导致编译时错误吗?
【问题讨论】:
标签:
c++
visual-c++
visual-studio-2005
【解决方案1】:
这是正确的行为。可以这样想:ClassB 的所有实例都有成员 ClassA::foo,但并非所有 ClassA 的实例都有成员 ClassB::foo;只有那些实际上是ClassB 实例的基类子对象的ClassA 实例才有它。因此,将ClassB::foo 分配给ClassAFoo,然后将ClassAFoo 与“纯”ClassA 对象结合使用会尝试调用不存在的函数。
如果你把foo从ClassB中去掉,表达式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”**