C++:指向虚拟成员函数的单态版本的指针?

发布于 2024-10-18 12:14:27 字数 789 浏览 3 评论 0原文

在 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 上调用的。但是,我一直无法找到一种方法来做到这一点。是否可以?

(除了编写一个新的非虚函数来进行单态调用,然后获取指向该函数的指针的繁琐手动方式之外。)

In C++, it's possible to get a pointer to a (non-static) member function of a class, and then later invoke it on an object. If the function was virtual, the call is dispatched dynamically depending on the dynamic type of the object. It's also possible (not using a member pointer) to call virtual member functions of objects monomorphically, by explicitly providing the scope containing the version to use. The following code demonstrates this:

#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
}

What I would like to do is combine the two, and get a pointer to the monomorphic version of a member function; i.e., I want a pointer to Foo::foo which always calls the base class version of foo, and prints 1, even if it is invoked on a Foo2. However, I haven't been able to find a way to do this. Is it possible?

(Other than the tedious manual way of writing a new non-virtual function which makes the monomorphic call, and then getting a pointer to that.)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

2024-10-25 12:14:28

为了详细说明包装函数的代码示例(尽管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
}

To elaborate with a code example for a wrapper function (and despite the fact the OP wanted to avoid this method!) as in many cases this is the pragmatically preferable solution:

#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
}
静谧幽蓝 2024-10-25 12:14:27

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

您可以做两件事:

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

It's possible in GCC, but the way it's documented in C++ language extensions section suggests there's no portable way to do it.

You can do two things:

  1. If you control the class, create a non-virtual function and a virtual wrapper for it and when you know you don't need virtual dispatch, just take address of the non-virtual one.
  2. If you don't, create a template functor that will hold the member pointer and do the explicit scope call.
好菇凉咱不稀罕他 2024-10-25 12:14:27

换句话说:你想作弊。

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

In other words : you want to cheat.

No, it is not possible because that is how the polymorphism in combination with pointer to member method works.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文