2012-12-13 102 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()'方法。 –