【问题标题】:C++: Pointer to monomorphic version of virtual member function?C ++:指向虚拟成员函数的单态版本的指针?
【发布时间】:2011-07-01 04:18:59
【问题描述】:

在 C++ 中,可以获取指向类的(非静态)成员函数的指针,然后在对象上调用它。如果函数是虚拟的,则调用将根据对象的动态类型动态分派。通过显式提供包含要使用的版本的范围,也可以(不使用成员指针)单态地调用对象的虚拟成员函数。下面的代码演示了这一点:

#include <iostream>
using std::cout; using std::endl;

struct Foo
{
    virtual void foo() { cout << 1 << endl; }
};

struct Foo2: public Foo
{
    virtual void foo() { cout << 2 << endl; }
};

int main( int, char** )
{
    Foo *foo = new Foo2;

    void (Foo::*foo_pointer)() = &Foo::foo;

    foo->foo();            // prints 2
    foo->Foo::foo();       // prints 1
    (foo->*foo_pointer)(); // prints 2
}

我想做的是将两者结合起来,并获得一个指向成员函数的单态版本的指针;即,我想要一个指向 Foo::foo 的指针,它总是调用 foo 的基类版本,并打印 1,即使它是在 Foo2 上调用的。但是,我还没有找到一种方法来做到这一点。有可能吗?

(除了繁琐的手动编写新的非虚拟函数来进行单态调用,然后获取指向它的指针。)

【问题讨论】:

  • 一个新的 SO 用户用可编译代码 sn-ps 提出一个好问题?现在我每天都看不到! :-)
  • 一个相当棘手的问题。
  • 我想知道您为什么要这样做,以及是否没有更好的方法来实现您想要实现的任何目标。 (哦,我不认为这是可能的,但 C++ 总是让我感到惊讶,所以我不会脱口而出这么说的答案。)
  • @illissius:您是否考虑过使用 lambdas 或 std::function 来做到这一点? GCC 和 VC10 支持这些。
  • @illissius:你如何知道一个虚函数是否被其他语言覆盖?

标签: c++ virtual-functions member-function-pointers


【解决方案1】:

这在GCC 中是可能的,但它在 C++ 语言扩展部分中记录的方式表明没有可移植的方式来做到这一点。

你可以做两件事:

  1. 如果您控制该类,请为其创建一个非虚拟函数和一个虚拟包装器,当您知道不需要虚拟调度时,只需获取非虚拟函数的地址即可。
  2. 如果不这样做,请创建一个模板仿函数来保存成员指针并执行显式范围调用。

【讨论】:

  • 绑定函数指针(通常称为委托)完全是另外一回事。
  • 不,这似乎正是我想要的(并同意如果它是 GCC 扩展,可能没有符合标准的方法)。这与代表无关;它将通过 vtable 的 void (Foo::*)() 转换为不通过 vtable 的 void (*)(Foo*)。这又是我想要的。非常感谢!
  • @Jan Hudec “如果您不这样做,请创建一个模板仿函数来保存成员指针并进行显式范围调用。”?如何正确理解?能给我一个简单的代码sn-p吗?
  • 加入@John——我自己一直没能创建这样一个模板(static_cast 创建一个临时副本破坏了我的尝试......)——所以真的很好奇这会如何看起来像! (是的,我知道我已经很晚了——即使使用最新的 C++ 标准也失败了......)。
  • 需要发现 GCC 扩展需要一个静态转换到 base - 而不是引用或指针 - 才能实际调用 base 函数;指针或引用没有落地虚拟性:(
【解决方案2】:

换句话说:你想作弊。

不,这是不可能的,因为这就是多态性与指向成员方法的指针相结合的工作原理。

【讨论】:

  • 多态的工作方式。正如提问者所展示的,可以使用语法foo-&gt;Foo::foo(); 进行所需的“作弊”调用。这不是成员函数指针的工作方式。
  • @Steve 你是对的。我会修改我的答案。但真正的答案是两者的结合:这就是多态性与指向成员方法的指针相结合的工作原理。
【解决方案3】:

详细说明包装函数的代码示例(尽管 OP 想要避免这种方法!),因为在许多情况下,这是务实的优选解决方案:

#include <iostream>
using std::cout; using std::endl;

struct Foo
{
    virtual void foo() { cout << 1 << endl; }
};

struct Foo2: public Foo
{
    virtual void foo() { cout << 2 << endl; }
};

void monomorphicFooFoo( Foo * f ) { f->Foo::foo(); }

int main()
{
    Foo *foo = new Foo2;

    void (*baseFoo)( Foo * ) = &monomorphicFooFoo;
    baseFoo( foo ); // Prints 1
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-02
    • 2010-11-02
    • 1970-01-01
    相关资源
    最近更新 更多