2013-05-19 96 views
1

我正在寫一個類,我想有一些成員方法有一些與它們相關的數據,特別是他們需要使用的機器人的機械系統。我以爲我可以把它們寫的函子,這樣的事情(這不是我的實際代碼):C++類的私人成員函數

class MyRobot : public Robot { 
public: 
    MyRobot(); 
    void runRobot(); 
private: 
    Command do_something_, 
      do_another_thing_; 
} 

,然後用類似的構造函數初始化的λ​​:

do_something_([] { 
    do_first_thing(); 
    do_second_thing(); 
}); 

然後告訴​​什麼要求它具有:

do_something_.requires(system_a); 
do_something_.requires(system_b); 

而在runRobot()我會告訴機器人的調度來執行這些命令:

void MyRobot::runRobot() { 
    scheduler.add(do_something_); 
    scheduler.add(do_another_thing_); 
} 

但我已經認識到,隨着命令的數量的增加,爲MyRobot少便於管理的構造會變得,因爲每個命令將有它的身體在那裏定義。我可以爲每個命令創建相應的私有方法,並用函數指針而不是lambda來初始化它們,但這似乎更復雜。我也可以爲每個特定命令劃分Command,從而在每個文件的獨立文件中包含主體和需求,但是對於一個相當簡單的任務來說,這感覺像是很多開銷。有沒有一種好方法可以做到這一點,我不知道?

+0

爲什麼沒有他們那樣簡單成員函數,並在那裏你將它們傳遞給調度綁定他們需要在該點的數據(通過'的std :: bind'或只是一個簡單的拉姆達)? – Xeo

+1

無關:請不要使用C++函數對象的名稱「函子」。我知道它被很多人使用;我要求大家避免它。這是一個誤用。這個詞在CS和數學中有着明確的含義,如果我們不把它用於完全不相關的事情,每個人都會變得更好。 –

+1

@ n.m。我知道分類理論中的函子是什麼,但考慮到「函子」是C++環境中最常用的術語,我將繼續使用它。 –

回答

0

您可以定義Command類以獲取std::function和「要求」的初始化程序列表。然後,而不是使用lambda表達式,您可以使do_somethingdo_another_thing它們自己的私有成員函數,因此您不必在構造函數中定義它們的實體。最後,在構造函數中,您可以通過將私有成員函數與當前MyRobot實例的這個指針綁定來構造Command實例,同時也爲它們提供了一個需求列表。 Command對象應該能夠修改MyRobot實例的私有狀態。下面是一個例子。另請參閱example output

#include <functional> 
#include <iostream> 
#include <vector> 

enum System { SYS_A, SYS_B, SYS_C }; 

class Command { 
public: 
    typedef std::function<void()> FuncType; 

    Command(FuncType func, std::initializer_list<System> requirements) 
    :func_(func), requirements_(requirements) { } 

    void operator()() { 
    std::cout << "Executing Command:" << std::endl; 
    for (System s : requirements_) 
     std::cout << " REQUIRES " << static_cast<int>(s) << std::endl; 
    func_(); 
    } 

private: 
    FuncType   func_; 
    std::vector<System> requirements_; 
}; 

class Scheduler { 
public: 
    void add(Command c) { 
    c(); 
    } 
}; 

class Robot { 
public: 
    Robot() 
    :do_something_ (std::bind(&Robot::do_something, this),  {SYS_A, SYS_B}), 
    do_another_thing_(std::bind(&Robot::do_another_thing, this), {SYS_A, SYS_C}) { } 

    void runRobot() { 
    s_.add(do_something_); 
    s_.add(do_another_thing_); 
    } 

private: 
    void do_first_thing() { std::cout << " FIRST THING!" << std::endl; } 
    void do_second_thing() { std::cout << " SECOND THING!" << std::endl; } 
    void do_third_thing() { std::cout << " THIRD THING!" << std::endl; } 

    void do_something()  { do_first_thing(); do_second_thing(); } 
    void do_another_thing() { do_first_thing(); do_third_thing(); } 

    Command do_something_; 
    Command do_another_thing_; 
    Scheduler s_; 
}; 

int main(int, char**) { 
    Robot().runRobot(); 
}