2010-11-01 47 views
2

我找了一個很好的模式來實現如下:C++:成員參照父

class Outer; 


class Inner 
{ 
    Outer * m_outer; 

    public: 
    InitOuter(Outer * o) { m_outer = o; } 
} 

class Outer 
{ 
    Inner m_inner; 

    public: 
    Outer() 
    { 
     m_inner.InitOuter(outer); 
    } 
} 
  • 內應始終以外
  • m_outer參考創建永遠不會爲
  • Inner

不幸的是,一生中

  • m_outer不會改變,據我所知,m_outer不能既不是參考也不是不可變的指針,如下面的初始化無效:

    Inner::Inner(Outer & o) : m_outer(o) {} 
    Outer::Outer() : m_inner(*this) {} 
    

    因爲在的m_inner初始化,Outer沒有被完全構造並由此this是無效的(並且也可以改變在進一步初始化期間)。

    我發現的唯一選擇是使Inner的構造函數非公開,的朋友。這有點好一些,但「朋友」關係似乎是強大的(因爲通常內部類應該封裝功能)。

    你如何實現這個?


    動機:在我的C++的理解,「外」還沒有完全建立,所以訪問this可能在法律上引發未定義行爲(任何人都可以證實這一點 - 甚至更好,它是不是這樣的?)。


    不,我不需要Inversion Of Control這裏。真的,謝謝你,但不。
    我省略了諸如隱藏副本CTor +賦值等細節。

  • +2

    我不知道IOC的含義。 – 2010-11-01 14:16:21

    +1

    @Johannes Schaub我也是。但我從google的結果中挑選了「國際奧委會」的「反控制」。 – 2010-11-01 14:20:45

    +0

    恩,從我對國際奧委會的理解,二者注入和建設者注入都是*國際奧委會的實施* ...難以避免,如果在內蒙古的任何時候你要委託一些東西到外... – Nim 2010-11-01 14:37:40

    回答

    8
    Inner::Inner(Outer & o) : m_outer(o) {} 
    Outer::Outer() : m_inner(*this) {} 
    

    這很好。就這樣做吧。還要考慮Inner是否可以是一個嵌套類(對於類似於迭代器的東西,這很有意義)。

    你還沒有對你嘗試建模的東西有任何說法。應該指出的是,外部也需要有一個自己的拷貝構造函數和拷貝賦值操作符或禁用它,否則平面拷貝會導致重大災難

    3

    在初始化列表中使用this指針會在Visual Studio 2008中生成編譯器警告C4355。基於文檔,它不是建議的做法是這樣做,因爲您將指向未構造對象的指針傳遞給另一個對象。如果該另一個對象的構造函數訪問任何構造函數或調用未構造對象的方法,結果是不確定的。

    但是,在您顯示的有限情況下,您沒有做任何會導致未定義行爲的事情。您只是將m_outer變量設置爲指向/引用未構建的對象。只要你限制它,你可以做到這一點,只要編譯器警告不是一個顯示限制器(我們的項目有一個標準,所有的編譯器警告都將被刪除)。

    如果這仍然困擾你,你可以改變這樣的代碼。

    class Outer; 
    
    class Inner 
    { 
        const Outer & m_outer; 
    
        public: 
        Inner(const Outer & o) : m_outer(o) 
        { 
        } 
    } 
    
    class Outer 
    { 
        Inner * m_inner; 
    
        public: 
        Outer() 
        { 
         m_inner = new Inner(*this); 
        } 
    } 
    
    +0

    明智的修改可能是從boost :: noncopyable之類派生外部函數,或者實現複製構造函數和賦值運算符,並對m_inner使用std :: auto_ptr。 – 2010-11-01 14:41:02

    +0

    是的,同意了。這絕對是一個純粹的骨骼實現,僅用於演示目的。 – 2010-11-01 14:42:51

    +0

    「提供編譯器警告不是一個顯示停止符(我們的項目有一個標準,所有編譯器警告都將被刪除)」只需添加一個#pragma警告(禁用:..)! – Adesit 2010-11-01 15:46:43