繁体   English   中英

C ++非成员访问成员函数

[英]C++ nonmember accessing member functions

我正在与其他团队合作进行项目。 另一个团队正在构建一个GUI,就像大多数GUI框架一样,该GUI也非常受继承驱动。 另一方面,这方面的代码(我想可能可以说是“底端”)本质上是C(尽管我相信通过MSVC2010工具链,从技术上讲,它们全都是C ++,而没有“按C对待”标志)。

这两个模块(UI和this)必须分别编译,然后链接在一起。

问题:出现了一种需求,即需要在底端调用GUI端提供了一些数据的重绘函数。 现在这是发生问题的地方。 您如何调用INTO一组成员函数,尤其是一个带有复杂依赖项的成员函数? 如果我尝试包括window标头,则有一英里长的GUI东西有一个继承列表,最底端显然不是针对复杂的GUI库构建的...我无法向前声明我的出路,因为我需要在窗口上调用一个函数?

现在显然这是一个主要的通信设计缺陷,尽管我们现在处境很糟,无法真正进行重大重组。

问题:

  1. 它应该如何组织从最底端到最顶端以进行重画,从像C的代码球到C ++节点的球。

  2. 我现在该怎么做才能解决此问题?

我能想到的唯一好方法是使用某种通信类...但是我看不到它不会遇到相同的问题,因为它需要同时针对GUI和底端进行构建?

如果您只需要调用一个函数,甚至是一小部分函数,​​则回调可能是您的最佳选择。 如果要处理成员函数,则仍可以使用指向成员函数的指针和指向相关对象的指针来调用它。 有关此操作的详细信息,请参见此答案。 但是,这可能意味着要求您为GUI代码包括一英里的依赖关系的整个列表。

编辑:经过深思熟虑,您可以对一些函数进行回调,而无需包括GUI代码的依赖项。 例如:

在GUI代码中的某处...

int DoFooInBar(int arg1, const char *arg2){
    return MyForm.ChildContainer.ChildBox.ChildButton.Bar.DoFoo( arg1, arg2 );
}

现在在GUICallbacks.hpp ...

int DoFooInBar(int arg1, const char *arg2);

然后,您可以包含GUICallbacks.hpp并从C代码中的任何位置调用DoFooInBar() 这种方法的唯一问题是,您需要为每个要使用的回调创建一个新函数。

批量完成此类任务的更通用方法是通过传递消息。 如前所述,一种非常跨平台的方法涉及一个通信对象。 如果提供一种通过命名机制获取指向共享通信对象的指针的机制,则不一定会遇到任何构建问题。 一个小例子是:

class CommObj{
public:
    struct Message{
        uint32_t type;
        uint32_t flags;
        std::string title;
        std::string contents;
        ... //maybe a union here or something instead
    };
private:
    static map<std::string, CommObj*> InternalObjects;
    std::deque<Message> Messages;
    std::string MyName;
public:
    CommObj(const char *name); //Registers the object in the map
    ~CommObj(); //Unregisters the object in the map
    void PushMessage( uint32_t type, uint32_t flags, const char *title, const char *contents, ...);
    Message GetMessage();
    bool HasMessages();
    static CommObj *GetObjByName(const char *name);
    static bool ObjWithNameExists();
};

显然,您可以制作一个更像C的版本,但是为了清晰起见,此版本使用C ++。 实现细节是读者的练习。

使用此代码,您可以然后简单地针对此对象构建后端和前端,然后可以在代码的两侧运行检查以查看是否已创建名称为"Backend->GUI" 如果没有,那就做。 然后,您可以通过使用GetObjByName("Backend->GUI");指向该对象的指针来开始与此对象进行通信GetObjByName("Backend->GUI"); 然后,您将连续轮询对象以查看是否有任何新消息。 您也可以为GUI提供另一个对象,以将消息发布到后端,也许名为"GUI->Backend" ,或者您可以在对象本身中建立双向性。

另一种方法是使用套接字通信/共享文件描述符。 然后,您可以在套接字中读取和写入数据,以供另一侧提取。 对于基本信令,这可能是完成所需内容的简单方法,尤其是在您实际上不需要复杂的内容时。 对套接字描述符的简单send()调用将是您需要发信号通知代码另一端的全部。

请注意,如果使用套接字过多,可能会导致速度降低。 它取决于基础实现,但是localhost上的套接字通常比原始函数调用慢。 但是,您可能不需要紧密循环中的互锁信号,因此您可以使用这两种方法都可以。 当我说慢一点时,我的意思是可能是50微秒和5微秒。 在大多数情况下,不必担心太多,但要注意。 另一方面,如果GUI代码与后端代码在不同的线程中运行,则您可能希望在发布/读取消息之前对通信对象进行互斥,而共享文件描述符则不需要。 互斥体/信号量会随身携带。

使用我概述的通信对象将允许您自动对类型进行封送处理,您可能会对此感兴趣。当然,您也可以编写一个对象来使用套接字进行封送处理,但是此时您可以最好使用共享对象。

希望您的项目能顺利进行。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM