【问题标题】:Calling base class definition of virtual member function with function pointer用函数指针调用虚成员函数的基类定义
【发布时间】:2010-11-15 11:30:48
【问题描述】:

我想使用成员函数指针调用虚函数的基类实现。

class Base {
public:
    virtual void func() { cout << "base" << endl; }
};

class Derived: public Base {
public:
    void func() { cout << "derived" << endl; }

    void callFunc()
    {
        void (Base::*fp)() = &Base::func;
        (this->*fp)(); // Derived::func will be called.
                       // In my application I store the pointer for later use,  
                       // so I can't simply do Base::func().
    }
};

在上面的代码中,func 的派生类实现将从 callFunc 中调用。有没有办法可以保存指向 Base::func 的成员函数指针,或者我必须以某种方式使用using

在我的实际应用程序中,我使用 boost::bind 在 callFunc 中创建了一个 boost::function 对象,稍后我用它从程序的另一部分调用 func。因此,如果 boost::bind 或 boost::function 有某种方法可以解决这个问题,那也会有所帮助。

【问题讨论】:

标签: c++ virtual function-pointers boost-bind


【解决方案1】:

当您通过引用或指针调用虚拟方法时,您将始终激活虚拟调用机制以找到最派生的类型。

最好的办法是添加一个非虚拟的替代函数。

【讨论】:

    【解决方案2】:

    不幸的是,您尝试做的事情是不可能的。指向成员函数的指针设计以保持所指向函数的虚拟性。

    【讨论】:

      【解决方案3】:

      您的问题是成员函数指针与裸函数指针并不完全相同。它实际上不仅仅是一个指针,而是一个considerably more complex structure,它在编译器实现级别的细节上有所不同。当您通过语法(this-&gt;*fp)() 调用它时,您实际上是在原始对象上调用它,这会导致虚函数调度。

      可能有用的一件事是将其转换为非方法指针类型。这有点吱吱作响,但我认为它应该可以工作。你仍然需要传递一个Base *,但是你明确地这样做了,并且虚拟函数调度被绕过了:

      typedef void BasePointer(Base*);
      
      void callFunc()
      {
          BasePointer fp = (BasePointer *)&Base::func;
          fp(this);
      }
      

      更新:好的,不,你不能那样做。这是非法的,如果合法的话就不安全了。 C++ FAQmore on this。但是知道这并不能解决你的问题。问题是,如果您想通过Base 指针调用Base::func,则指向对象的指针或指向成员的指针,它指向的对象必须是Base .如果你可以安排,那么你可以使用成员函数指针。

      这是另一个想法,不漂亮,但至少可行。在Derived 中提供一个非虚拟函数,显式调用Base::func。而是指向那个。如果您需要在 funccallFunc 的许多不同变体的一般情况下执行此操作,它不会扩展,但它适用于一种方法。

      【讨论】:

      • 那绝对不会工作!比较 sizeof(&amp;Base::func)sizeof(BasePointer) :o
      • mmutz:是的。我总是在发布之前尝试进行测试,而今天我没有给自己留出时间去做。 可能static_cast 可能足够聪明,可以将函数指针部分从成员函数指针中弹出,但恐怕我的 Python 函数概念现在覆盖了我的 C++ :)。
      • 这是错误的:“它不仅携带要调用的函数的地址,还携带要调用它的对象”
      • Eric:你能给我指点这方面的一些文件吗?我的理解是成员函数指针具体是函数指针与成员指针的配对。这就是为什么sizeof(&amp;Base::func) 在我尝试过的每个编译器上都是普通指针的两倍。
      • @quark:“&Base::func”中的“对象”是什么? “Base”是一种类型,而不是一个实例。另请注意,使用指针时必须提供实例。 (例如:BasePointer fp = &Base::func; Base b; b.*fp();)。
      【解决方案4】:

      通过函数指针这样做有什么具体原因吗?

      你应该可以写:

      Base::func();
      

      调用基类实现。

      【讨论】:

      • 正如我在问题中所写,我将指针保存在 callFunc 中,但使用它从程序中的另一个位置实际调用 func。
      • 对于虚函数,这是行不通的。它总是会做一个 vtable 查找并调用派生类上的方法。
      【解决方案5】:

      除了夸克所说的,更一般的评论是你应该使用信号/槽实现而不是裸函数指针。 Boost 有一个,还有 libsigc 和许多其他的。

      【讨论】:

        【解决方案6】:

        这是怎么回事?

        (Base(*this).*fp)();
        

        现在,如果您对此感到满意,就会提出一个问题,即为什么您首先还要使用函数指针。我认为更多上下文可能会有所帮助。

        【讨论】:

        • quark 已经建议了这一点(“...如果你想通过 Base 指针调用 Base::func,它指向的对象也必须是 Base。”)。我假设 Eddie 不能保证他知道调用函数时要切片的类型。
        猜你喜欢
        • 2015-06-28
        • 1970-01-01
        • 2018-11-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-01-31
        • 2013-06-29
        相关资源
        最近更新 更多