2012-07-10 155 views
18

我對C++相對來說比較新,並且我已經爲這個事物找到了很多答案,但是我從來沒有得到滿意的答案。訪問外部類的內部類

比方說,我有一個名爲FSM的結構。最終在我的代碼中,可以創建多個FSM實例。 FSM的屬性之一是int X這不是靜態的,FSM的每個實例都應該有自己的值X。現在

FSM的屬性之一是另一種結構submachine這需要讀取的X這樣的值:

struct FSM 
{ 
    public: 
    int x; 

    int getX(){return x;} 

    struct submachine 
    { 
     void onentry() {int g = getX();}; 
    }; 
}; 

這提供了以下錯誤:

Error: 'FSM::getX' : illegal call of non-static member function

我的問題是,submachineFSM的成員,所以不應該有權訪問FSM所有屬性的本地實例?如果不是,當我們創建FSM的實例時,我們是不是要創建其所有成員的實例,即submachine?如果是這樣,那麼爲什麼我們需要創建一個對象onentry()需要?

我假設編譯器是正確的,所以我也想知道是否有辦法使這項工作。

注意:不幸的是,內部結構(submachine)的實例在調用事件時被實例化,因此我只能定義類型,而不是在FSM中爲它們實例化對象。

回答

34

my question is, submachine is a member of FSM, so it should have access to local instances of all the attributes of FSM, no?

不是。與Java不同,內部類對象不具有對外部對象的隱式引用。

wouldn't we be creating an intance of all its members i.e. submachine?

submachine是一個類型,而不是一個成員變量。如果你想要一個成員變量,你必須做這樣的事情:

struct FSM { 
    struct submachine { 
     ... 
    }; 

    submachine sm; // Member variable of type submchine 
}; 

如果你想sm「看到」它的父對象,你需要明確地傳遞:

struct FSM { 
    struct submachine { 
     FSM &parent; // Reference to parent 
     submachine(FSM &f) : parent(f) {} // Initialise reference in constructor 
    }; 

    submachine sm; 

    FSM() : sm(*this) {} // Pass reference to ourself when initialising sm 
}; 

請注意,同樣的原則適用於不是成員變量的submachine。如果您希望他們能夠訪問FSM實例,則需要將引用傳遞給一個實例。

還請注意,您可以使用指針而不是引用。事實上,指針在許多情況下提供了更大的靈活性。

+0

如果有一種方法可以完成我想完成的任務嗎? – Kam 2012-07-10 00:30:48

+2

Downvoter:關心分享? – 2012-07-10 00:33:51

+0

(對不起,延期,找到鏈接)。嵌套類是成員,可以像任何其他成員一樣訪問外部類,請參閱[DR 45](http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#45),它是自2003年以來的標準 – 2012-07-10 00:35:54

2

請注意,聲明struct submachine只定義了類型;它實際上並不在該類的類中創建一個字段。

您需要執行下列操作之一:

struct submachine mysub; // creates a field after the class is defined 

struct submachine 
{ 
    . . . 
} mysub; // creates the field "mysub" also, as the structure is being defined 

這使得mysub領域,那麼你訪問它在你訪問x以同樣的方式。

submachine定義需要包括特定FSM(例如指針野外FSM*,而且很可能像submachine(FSM* fsm): fsm_(fsm) {}構造函數初始化它),這樣你可以說fsm_->getX()訪問一定X值。

+0

不幸的是,內部結構的實例被聲明爲運行時(事件),因此我只能定義類型,而不能爲它們創建實例化對象。 – Kam 2012-07-10 00:32:38

+2

你仍然不能'int g = getX();'沒有'FSM'對象。這是如何回答這個問題的? – 2012-07-10 00:35:09

1

我只是在猜測你想做什麼,但如果我的猜測是正確的,你可能會想到像下面這樣的東西。

struct FSM_Base { 
    int x; 

    struct submachine1; 
    struct submachine2; 

    FSM_Base() : x(0) {} 
    virtual ~FSM_Base() {} 
}; 

struct FSM_Base::submachine1 : virtual public FSM_Base { 
    void oneentry() { int g = x; } 
}; 

struct FSM_Base::submachine2 : virtual public FSM_Base { 
    void oneentry() { int g = x; } 
}; 

struct FSM : public FSM_Base::submachine1, 
      public FSM_Base::submachine2 { 
    FSM_Base::submachine1 * sub1() { return this; } 
    FSM_Base::submachine2 * sub2() { return this; } 
}; 
3

認爲在你的榜樣,我可以合法地寫一個免費功能

void foo() 
{ 
    FSM::submachine sub; 
    sub.onentry(); 
} 

那裏是沒有 FSM實例sub可以參考。

無論是作爲奧利說,有submachine對象存儲的引用其父FSM對象,或者只是經過的x值直接進入onentry(目前還不清楚它如何被調用的)。


從快速瀏覽一下Boost.MSM docs我發現non-default-constructed submachines此說明。

這是非常醜陋的,我不明白後端足以在這裏解釋它,並且字面代碼不會有足夠的意義孤立地值得粘貼。

從那裏也與該示例代碼顯示了衝鋒槍的具有以下簽名進入方法:

template <class Event,class FSM> void on_entry(Event const&,FSM&); 

如果這是正確的,你可以存儲指向你的外在狀態機on_entry,或提取的價值在那裏,並記錄在衝鋒槍。

+0

謝謝!這就是我一直在尋找的東西,現在我明白了。這篇文章與OLI的帖子一起爲我做了。我希望我能接受這兩個答案。 – Kam 2012-07-10 01:10:48