不同的行为:通过非静态成员指针直接调用函数

时间:2014-08-04 13:32:58

标签: c++ function-pointers

问题:

虽然我知道函数指针,但我无法理解是什么让这两个函数在Derived类中的行为不同:

I)StartPrintThroughFuncPtr()

II)StartPrint()

以下是完整代码,以及评论中其输出

#include "iostream"

class Base
{
    (void)(Base::*callee)(void);
    virtual void Print(){std::cout<<"Print: Base"<<std::endl;}

public:
    void StartPrintThroughFuncPtr(){
        callee = &Base::Print;
        (this->*callee)();
    }

    void StartPrint(){
        Base::Print();
    }
};

class Derived : public Base
{
    virtual void Print(){std::cout<<"Print: Derived"<<std::endl;}
};

void main()
{
    Base *basePtr = new Base;
    basePtr->StartPrintThroughFuncPtr();    //  ==> "Print: Base"
    basePtr->StartPrint();                  //  ==> "Print: Base"

    Derived *derivedPtr = new Derived;
    derivedPtr->StartPrintThroughFuncPtr(); //  ==> "Print: Derived"
    derivedPtr->StartPrint();               //  ==> "Print: Base"
}

谢谢=)

2 个答案:

答案 0 :(得分:3)

指向虚函数的指针实际上存储虚函数表中的偏移量,而不是指向函数的直接指针。这就是为什么通过它进行调用是虚拟的。

答案 1 :(得分:2)

指向成员函数的指针支持多态行为。当您创建指向虚函数的指针时,调用将调度到基于调用函数的对象的运行时类型的实现(在您的情况下,即basePtr或{{1 }})。范围分辨率运算符在那里并不重要,因为指向虚函数的函数指针不能完全定义目标。

  

C ++ 11标准,第4.11.2节:类型为“指向cv T类型B的成员的指针”的prvalue,其中B是类类型,可以转换为类型为“指向成员的指针”的prvalue类型为cv T“的D,其中D是B的派生类(第10节)。[...] 转换的结果是指与转换发生前指向成员的指针相同的成员,但是它将基类成员称为派生类的成员。(强调添加)

另一方面,

derivedPtr通过其范围解析运算符直接调用StartPrint类中的实现。