2012-09-01 120 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

感謝您的解決方案,我接受了另一個,因爲它只直接針對標題,但我也贊成這一個。 –