2015-05-28 47 views
0

我需要派生從類基的一類子與下列要求:構造一個對象,把它傳遞給基類的構造保持其壽命的控制

  1. 階級基礎構造函數接受一個引用對象Foo類。
  2. Foo類的對象應該具有與Child類的對象相同的生命週期。
  3. Foo,Child和Base的構造函數可以拋出,代碼應該充分地破壞到目前爲止創建的內容。
  4. 代碼是多線程的,孩子的許多構造函數可以同時調用
  5. Foo沒有拷貝構造函數,沒有默認構造函數。

(也有一些相似之處How to remind a param passed to the base class constructor? 但是異常安全幾乎沒有在上面提到的問題討論)

儘管實現它,我遇到以下困難:

A.這似乎自然有類Foo的對象是兒童中的一員

class Base { 
public: 
    Base(Foo& foo); 
}; 

class Child: public Base { 
public: 
    Child(int par); 
private: 
    Foo m_foo; 
}; 

不過,我現在該如何初始化它在兒童利弊tructor?

Child::Child(int par): 
Base(Foo(par)), 
m_Foo(par) ... 

這將通過臨時基類構造函數(它會甚至編譯?),然後初始化m_Foo分別。這不好。

如果沒有要求#4,#5,我可以用一個靜態方法,共同構建富時基本被調用,然後將它傳遞給m_Foo:

Foo Child::s_Helper(int par) { 
    if (!s_FooConstructed) { 
     s_Foo = Foo(par); 
     s_FooConstructed = true; 
    } 

    return s_Foo; 
} 

我喜歡使用的unique_ptr或shared_ptr的作爲子類成員:

class Child: public Base { 
public: 
    Child(int par); 
private: 
    unique_ptr<Foo> m_Foo; 
    bool m_IsFooConstructed; 
    unique_ptr<Foo> x_FooHelper(int par); 
}; 

Child::Child(int par): 
    Base(x_FooHelper(par)), 
    m_Foo(x_FooHelper(par)) 
{} 

unique_ptr <Foo> Child::x_FooHelper(int par) 
{ 
    if(!m_FooConstructed) { 
     m_Foo.reset(new Foo(par));  ///< Problem here 
     m_FooConstructed = true; 
    } 
    return m_Foo; 
} 

然而,這裏m_Foo不是在x_FooHelper被調用的時候建造... 用相同的shared_ptr

我可以創造,而不是一個指針:但是這裏

class Child: public Base { 
public: 
    Child(int par); 
private: 
    Foo* m_Foo; 
    bool m_IsFooConstructed; 
    Foo* x_FooHelper(int par); 
}; 
Child::Child(int par): 
    Base(*x_FooHelper(par)), 
    m_Foo(x_FooHelper(par)) 
{} 

Foo* Child::x_FooHelper(int par) 
{ 
    if(!m_FooConstructed) { 
     m_Foo = new Foo(par); 
     m_FooConstructed = true; 
    } 
    return m_Foo; 
} 

,如果基本構造函數拋出,美孚已經創建,因爲它是由原始指針(m_Foo)保留了它不會被破壞〜孩子也不會調用。我能做什麼?

回答

3

使用Base-from-Member Idiom - 創建另一個類擁有Foo作爲Child第一基:

class Base { 
public: 
    Base(Foo& foo); 
}; 

struct FooOwner { 
    FooOwner(int par) 
     : m_foo(par) 
    { } 

    Foo m_foo; 
}; 

class Child 
    : private FooOwner // first, so Foo is initialized 
    , public Base  // before Base 
{ 
public: 
    Child(int par) 
     : FooOwner(par) 
     , Base(FooOwner::m_foo) 
    { 
     /* something else */ 
    } 
}; 

Foo的壽命仍然依賴於Child,您可以安全地傳遞給參考它到Base - 因爲它肯定會在Base之前構建。

如果您發現太冗長出於某種原因,你也可以使用boost::base_from_member來實現同樣的事情:

class Child 
    : private boost::base_from_member<Foo> 
    , public Base 
{ 
    typedef boost::base_from_member<Foo> FooOwner; 

    Child(int par) 
     : FooOwner(par) 
     , Base(FooOwner::member) 
    { } 
}; 
+0

輝煌!非常感謝! – mzu

相關問題