2012-12-13 71 views
11

我有一個合成圖案實現,用於GUI組件:可能性混合複合模式和奇異遞歸模板模式

class CObject { 
private: 

    CObject * m_pParent; 
    CObjectContainer * m_pChildren; 

    void private_foo() { 
    this->foo(); 
    //Calls private_foo for each child in container. 
    m_pChildren->foo(); 
    } 

public: 
    virtual void foo() { 
    //empty for base class 
    } 

    virtual CObject * duplicate() { 
    //Do duplication code 
    return new CObject(*this); 
    } 

    virtual CObject * detach() { 
    //Remove this object (along with it's children) 
    //from current tree. 
    m_pParent->RemoveChild(this); 
    m_pParent = nullptr; 
    return this; 
    } 
} 

class CSpecificObject : public CObject { 
public: 
    virtual void foo() { 
    //Specific code for this class 
    } 

    virtual CSpecificObject * duplicate() { 
    //Overload, but the code only calls diferent constructor 
    return new CSpecificObject(*this); 
    } 

    virtual CSpecificObject * detach() { 
    //Note the code is identical. 
    m_pParent->RemoveChild(this); 
    m_pParent = nullptr; 
    return this; 
    } 
} 

不幸的是繼承類的數量迅速增加,並且重複的代碼(在給定的例子僅detach()方法)讓我頭疼。

有沒有辦法乾淨地實現detach()方法,保持返回類型與它所調用的對象相同?

我在想CRTP,但我不能想辦法,以保持動態多態性與編譯時多態性沿:

template <Child> 
class CObject { 
private: 
    ... 
    Child * detach() { 
    m_pParent->RemoveChild(this); 
    m_pParent = nullptr; 
    return static_cast<Child*>(this); 
    } 
    ... 
} 

//Array of CObject* pointers is no longer possible. 

回答

6

您可以添加一個抽象層次:

class CObjectBase 
{ 
    public: 
     // Other methods... 
     virtual CObjectBase* detach() = 0; 
     virtual CObjectBase* duplicate() const = 0; 
}; 

template <typename Child> 
class CObject : public CObjectBase 
{ 
    public: 
     // ... 
     Child* duplicate() const 
     { 
      return new Child(*static_cast<Child*>(this)); 
     } 

     Child* detach() 
     { 
      m_pParent->RemoveChild(this); 
      m_pParent = nullptr; 
      return static_cast<Child*>(this); // Cast needed here (inherent to CRTP) 
     } 
     std::vector<CObjectBase*> children; // Array possible now 
     // ... 
}; 

class MyObject : public CObject<MyObject> 
{ 
    // ... 
}; 

在自然語言中:所有對象的接口(CObjectBase)都有其子代的部分實現(CObject<Child>),它們只需要繼承此部分實現,從而減少了複製代碼的數量。

1

我在想CRTP,但我不能想辦法,以保持動態多態性與編譯時多態性沿

您可以通過提供一種利用CRTP某些接口默認的虛擬實現方式將它們混合樣式基類。

因此,您可以聚合CRTP基礎實現(可能配置了額外的'策略'模板參數),仍然可以覆蓋繼承類中的特定行爲。

微軟的ATL library使用了很多。 我也在我的STTCL state machine library中使用這種技術。

1

單從片段中不清楚爲什麼你需要detach()返回指向交付類型的指針。

要利用返回交付類型的detach(),無論如何都需要使用對交付類型的引用來調用它。就像這樣:

CSpecificObject* specific_object = new SpecificObject(); 
// ... 
specific_object->detach()->method_declared_in_specific_object(); 

但是,這可以用等價物來替換的作品即使分離無效:

specific_object->detach(); 
specific_object->method_declared_in_specific_object(); 

如果你有基本類型的引用,你不能拿的detach()優勢返回類型:

CObject* specific_object = new SpecificObject(); 
//... 
// !!! Won't compile: 
specific_object->detach()->method_declared_in_specific_object(); 

因此,目前尚不清楚您嘗試實施的方法有哪些優點。

一面不是duplicate()方法是臭的。當交付的類不覆蓋它時,它會中斷,但使用父類的默認實現。這可能是高端設計出現問題的標誌。

+0

'分離()'方法用於在醜陋的方式: 'CObject的* tree_of_stuff;' - 對象的完整樹 'CSpecificObject * specific_object = tree_of_stuff->子( 「的StringID」) - > detach();' 這裏'Child <>()'方法沿着樹進行搜索並將對象轉換爲指定的模板參數。如果'detach()'返回'void'或'CObject *',則此語法不可用。 –

+1

'duplicate()'方法是一定的錯誤來源,這是我用CRTP擴展當前模式的原因之一。在我看來,依靠複製構造函數是更安全的,承諾每個人都會實現'duplicate()'方法。 –