2012-09-01 51 views
0

我有以下类设置(这里只与相关内容):C++成员回调与向前声明

// Message.h 
class Message { }; 
typedef std::shared_ptr<Message> MessagePtr; 
// Task.h 
#include "Message.h" 

/* 
* On include of Communication.h compilation fails. 
*/ 

class Task { 
public: 
    send(const MessagePtr &msg) { 
     // Call to Communication::send 
    } 

    MessagePtr recv() { 
     // Call to Communication::recv 
    } 
}; 

typedef std::shared_ptr<Task> TaskPtr; 
// Base.h 
#include "Task.h" 

class Base { 
    std::map<TaskPtr, std::vector<TaskPtr>> taskMap; 
}; 
// Runtime.h 
#include "Base.h" 

class Runtime : public Base { }; 
// Communication.h 
#include "Base.h" 

class Message; // Forward declaration 

class Communication : public Base { 
public: 
    void send(const TaskPtr &caller, const MessagePtr &msg); 
    MessagePtr recv(const TaskPtr &caller); 
}; 

我的目标是一种提供在Communication之内的一个独立的通信层,让任务相互通信。接收者列表在taskMap(发送者不知道接收者的发布 - 订阅类型)内定义。

为此,我的想法是使用从TaskCommunication的回调函数(例如std::bind或类似的)。但是,我无法执行此操作,因为无论何时我将Communication标头内的Task编译失败,这是由于通告包含在内。

所以我不确定如何从Communication转发声明send/recvTask内使用它们。我已阅读this问题,这是类似的,也提供了很好的答案,我想避免在Task内放置指向Communication的指针。在我看来,最好的解决方案是为Communication的成员引入一种前向声明,但是我担心我不知道如何实现这一点。

我也想过班级设置,无论是否符合目的,但没有提出更好的解决方案。

+0

可您拆分代码分成单独的块所以很清楚哪些东西在头声明?也许一个评论显示你希望能够插入回调函数? – Oktalist

+0

完成后,还添加了当前的include和关于包含编译失败的注释。 –

+0

不错。现在'Task :: send()'和'recv()'从哪里获得'Communication'的实例?你真的在类定义中内联定义这些函数,还是在单独的'Task.cpp'文件中定义? (如果您可以简单回答这些问题,则无需编辑代码。) – Oktalist

回答

1

你可以把这个声明放在类之外。它不会阻止库仅作为标题,因为这些函数可能是inline。你可以安排的功能,如:

// Task.h 
#include "Message.h" 

class Task { 
public: 
    inline void send(const MessagePtr &msg); 
    inline MessagePtr recv(); 
// ^^^^^^ 
}; 

typedef std::shared_ptr<Task> TaskPtr; 

// Communication.h 
#include "Base.h" 
#include "Task.h" 

class Communication : public Base { 
public: 
    void send(const TaskPtr &caller, const MessagePtr &msg); 
    MessagePtr recv(const TaskPtr &caller); 
}; 

// Task.impl.h 
#include "Communication.h" 

inline void Task::send(const MessagePtr &msg) { 
    // call Communication::send 
} 

inline MessagePtr Task::recv() { 
    // call Communication::recv 
} 

,包括Task.impl.h有定义的两个任务的方法。

+0

哦!从未想过定义另一个标题并使用'inline'。谢谢。 –

1
// Task.h 
#include "Message.h" 

class Task { 
public: 
    typedef std::function<void(const MessagePtr&)> SendFunc; 
    typedef std::function<MessagePtr()> RecvFunc; 
private: 
    SendFunc sendfunc; 
    RecvFunc recvfunc; 
public: 
    void setSendFunc(SendFunc& f) { sendfunc = f; } 
    void setRecvFunc(RecvFunc& f) { recvfunc = f; } 

    send(const MessagePtr &msg) { 
     if (sendfunc) { /* call sendfunc */ } 
    } 
    MessagePtr recv() { 
     if (recvfunc) { /* call recvfunc */ } 
    } 
}; 

typedef std::shared_ptr<Task> TaskPtr; 
// Communication.h 
#include "Base.h" 

class Communication : public Base { 
public: 
    void send(const TaskPtr &caller, const MessagePtr &msg); 
    MessagePtr recv(const TaskPtr &caller); 
}; 
// in a function somewhere 
taskptr->setSendFunc(std::bind(Communication::send, communicationInstance, taskptr)); 
taskptr->setRecvFunc(std::bind(Communication::recv, communicationInstance, taskptr)); 
+0

感谢您的解决方案,我接受了另一个,因为它只直接针对标题,但我也赞成这一个。 –