“界面”类似于 boost::bind 的语义

发布于 2024-09-29 05:54:18 字数 1817 浏览 2 评论 0原文

我希望能够将 Java 的接口语义与 C++ 结合起来。首先,我使用 boost::signal 来回调给定事件的显式注册成员函数。这非常有效。

但后来我发现一些函数回调池是相关的,因此将它们抽象出来并立即注册所有实例的相关回调是有意义的。但我了解到的是,boost::bind 的特定性质和/或获取 this 的值似乎打破了这一点。或者可能只是 add_listener(X &x) 方法声明更改了 boost::bind 生成的代码。

我对问题发生的原因有一个非常粗略的了解,并且我认为它可能按照其设计正常运行。我很好奇:我应该做什么?当然有一个正确的方法来做到这一点。

这是一些示例代码:

#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <iostream>

using namespace std;

struct X;
struct Callback
{
    virtual void add_listener(X &x) = 0;
};

struct X
{
    X() {}
    X(Callback &c) {  c.add_listener(*this); }
    virtual void go() { cout << "\t'" << __PRETTY_FUNCTION__ << "'" << endl; }
};

struct CallbackReal : public Callback
{
    virtual void add_listener(X &x)
    {
        f = boost::bind<void>(boost::mem_fn(&X::go), x);
    }

    void go() { f(); }

    boost::function<void (void)> f;
};


struct Y : public X
{
    Y() {}

    Y(Callback &c) {  c.add_listener(*this); }
    virtual void go() { cout << "\t'" << __PRETTY_FUNCTION__ << "'" << endl; }
};


int main(void)
{
    CallbackReal c_x;
    CallbackReal c_y;

    X x(c_x);
    Y y(c_y);

    cout << "Should be 'X'" << endl;
    boost::bind<void>(boost::mem_fn(&X::go), x)();

    cout << "Should be 'Y'" << endl;
    boost::bind<void>(boost::mem_fn(&X::go), y)();

    cout << "------------------" << endl;

    cout << "Should be 'X'" << endl;
    c_x.go();
    cout << "I wish it were 'Y'" << endl;
    c_y.go();

    return 0;
}

好吧,我没有完全描述问题。标题具有误导性。

哦,伙计。否决这个。显然我没有很好地描述问题,我认为这最终归结为主要是语法错误。 :(

I wanted to be able to have something like Java's interface semantics with C++. At first, I had used boost::signal to callback explicitly registered member functions for a given event. This worked really well.

But then I decided that some pools of function callbacks were related and it made sense to abstract them and register for all of an instance's related callbacks at once. But what I learned was that the specific nature of boost::bind and/or taking the value of this seemed to make that break. Or perhaps it was just the fact that the add_listener(X &x) method declaration changed the code that boost::bind generated.

I have a very rough understanding why the problem occurred and I think it's probably functioning correctly as per its design. I am curious: what should I have done instead? Surely there's a Right Way to do it.

Here's some example code:

#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <iostream>

using namespace std;

struct X;
struct Callback
{
    virtual void add_listener(X &x) = 0;
};

struct X
{
    X() {}
    X(Callback &c) {  c.add_listener(*this); }
    virtual void go() { cout << "\t'" << __PRETTY_FUNCTION__ << "'" << endl; }
};

struct CallbackReal : public Callback
{
    virtual void add_listener(X &x)
    {
        f = boost::bind<void>(boost::mem_fn(&X::go), x);
    }

    void go() { f(); }

    boost::function<void (void)> f;
};


struct Y : public X
{
    Y() {}

    Y(Callback &c) {  c.add_listener(*this); }
    virtual void go() { cout << "\t'" << __PRETTY_FUNCTION__ << "'" << endl; }
};


int main(void)
{
    CallbackReal c_x;
    CallbackReal c_y;

    X x(c_x);
    Y y(c_y);

    cout << "Should be 'X'" << endl;
    boost::bind<void>(boost::mem_fn(&X::go), x)();

    cout << "Should be 'Y'" << endl;
    boost::bind<void>(boost::mem_fn(&X::go), y)();

    cout << "------------------" << endl;

    cout << "Should be 'X'" << endl;
    c_x.go();
    cout << "I wish it were 'Y'" << endl;
    c_y.go();

    return 0;
}

Okay, I did not describe the problem completely. The title is misleading.

Oh, man. Downvote this one. I obviously haven't described the problem well and I think this ultimately boils down to mostly a syntactical error. :(

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

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

发布评论

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

评论(2

廻憶裏菂餘溫 2024-10-06 05:54:18

boost::bind 按值获取其参数并复制它们。这意味着

f = boost::bind<void>(boost::mem_fn(&X::go), x);

将传递 x副本,这将切掉其中的 Y 部分(如果它确实是 Y< /code> 首先)。要使虚拟调度正常工作,您需要传递一个指向 boost::bind 的指针:(

f = boost::bind(&X::go, &x);

请注意,您实际上并不需要 mem_fn ,或者显式编写>,因为 boost::bind 和参数推导会为您处理这些问题。)

boost::bind takes its parameters by value and copies them. That means

f = boost::bind<void>(boost::mem_fn(&X::go), x);

will pass a copy of x, which will slice off the Y piece of it (if it was really a Y to begin with). To get virtual dispatch to work, you need to pass a pointer to boost::bind:

f = boost::bind(&X::go, &x);

(Note that you don't actually need mem_fn, or to explicitly write <void>, since boost::bind and argument deduction take care of those for you.)

旧人哭 2024-10-06 05:54:18

Java 接口并不专门存在于 C++ 中。您可以获得的最接近的是纯抽象基类。这通常已经足够接近了。

您的其余问题与接口无关。 Java 使用观察者模式进行事件连接和调度。接口部分只是轻微相关,因为观察者需要遵守特定的接口(当然,否则你将不知道要调用什么)。

使用 boost::bind 创建仿函数实际上是一种超越接口的抽象,因此是一种更通用的解决方案。观察者模式和函子被组合成信号/槽习惯用法/模式,并在各种库中实现,例如 boost::signals、boost::signals2 和 gtk++。 Qt 版本在机制上有很大不同,但在概念上相似。

那么,这意味着什么,可以帮助您了解什么、为什么以及在哪里?我建议首先搜索观察者模式是什么,并尝试编写一些实现。

Java interfaces don't specifically exist within C++. Closest you can get is pure abstract base classes. This is generally quite close enough.

The rest of your question is unrelated to interfaces. Java uses the Observer pattern for event connection and dispatch. The interface part is only mildly related because observers are required to obey specific interfaces (of course, since otherwise you wouldn't have any idea what to call).

Using boost::bind to create functors is actually an abstraction beyond interfaces and is thus a more generic solution. The observer pattern and functors are put together into signal/slot idiom/patterns implemented in various libraries like boost::signals, boost::signals2, and gtk++. The Qt version is quite different in mechanics but similar in concept.

So, what's this mean to help you understand what, why and where? I'd suggest starting with a search on what the Observer pattern is and try to write a few implementations.

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