【问题标题】:Calling a virtual function statically through a function pointer通过函数指针静态调用虚函数
【发布时间】:2010-12-03 13:02:56
【问题描述】:

请考虑以下代码。

#include <iostream>
#include <memory>

struct A {
  A() {}
  virtual void f() {
    std::cout << "A::f" << std::endl;
  }
private:
  A(const A&);
};

struct B : public A {
  virtual void f() {
    std::cout << "B::f" << std::endl;
    call(&A::f);
  }
private:
  void call(void (A::*aMethod)()) {
    // ...
    (static_cast<A&>(*this).*aMethod)();
    //(static_cast<A>(*this).*aMethod)();  -> not allowed to copy!
    // ...
  }
};

void main() {
  std::auto_ptr<B> b (new B);
  b->f();
}

此代码递归调用相同的B::f 方法,直到它耗尽堆栈,而我希望call 方法调用A::f。也就是说,它应该静态调用它,就像我简单地写下它通常会发生的那样:

struct B : public A {
  virtual void f() {
    std::cout << "B::f" << std::endl;
    // ...
    A::f();
    // ...
  }
};

我想要call 方法的原因是在“静态调用”之前和之后考虑一些代码,这些代码对于具有与f 相同签名的几种方法是通用的...

如何静态调用在运行时决定的虚函数?

【问题讨论】:

  • B::f中,为什么一定要通过call和一个函数指针来调用函数呢?为什么你不能只做 A::f(); ? (将“之前”和“之后”代码重构为一些通用函数或通用类。)
  • 这可能是我必须要做的... 方法 call 只是在这里分解代码,但我没有意识到我无法按照我的意图使用它...

标签: c++ static virtual


【解决方案1】:

这是意料之中的。对象表达式是对基类 A 的引用,因此当 A::f 是虚拟的时会触发虚函数机制(动态绑定)。

只有 :: 操作符可以抑制虚函数调用机制。

$10.3/12-“明确限定 范围运算符(5.1)抑制 虚调用机制。”

【讨论】:

  • 看来我不能在这里使用范围运算符:它会限定指针的名称,而不是指向的函数......
  • 是的,AFAICT,你必须选择 A::f
【解决方案2】:

当您使用指针时,您的覆盖已解决,因此您在这里想要的东西不容易通过这种方式实现。您可以做的最好的事情是调用您的函数的包装器 - 无论是外部的东西,还是调用您的函数的非虚拟函数。如果您有 C++0x 功能,则可以使用 lambda,这是 IMO 最干净的解决方案。

您可能想重新考虑使用前/后功能的方式来解决您的问题:它们可以通过重载“->”运算符来实现。

【讨论】:

  • 不幸的是,重载 operator-> 不适用于实际情况,因为它适用于任何调用的方法,而不仅仅是 f 和其他类似的方法......但无论如何谢谢......
  • 是的,这通常是个问题。但是,也许您可​​以重构代码以将这些方法放入单独的接口类中。或者只是在您的虚拟函数的调用站点上应用包装运算符,例如 Call(myObject)->f();
  • 实际上,你甚至不需要超载 -> 对于最后一个想法。只需实现“Call”类型的 ctor 和 dtor 就足够了。
猜你喜欢
  • 2011-12-22
  • 2012-05-05
  • 1970-01-01
  • 1970-01-01
  • 2013-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多