返回模板子类

时间:2011-05-04 23:59:20

标签: c++ templates return subclass

我有一堆容器和对象。容器和对象具有模板化的子类。那些模板化的子类具有专门的子类。在专门的对象中,我想要检索它们的容器。这是代码设置:

class Container;
template<class T> class SubContainer;

class Object
{
public:
  Object() : m_pContainer(NULL) { }

public:
  Container* GetContainer()
  {
    return m_pContainer;
  }

  void SetContainer(Container* pContainer)
  {
    m_pContainer = pContainer;
  }

private:
  Container* m_pContainer;
};

class Container
{
public:
  Container() : m_pObject(NULL) { }
  virtual ~Container() { }

public:
  void SetObject(Object* pObject)
  {
    m_pObject = pObject;
    m_pObject->SetContainer(this);
  }

protected:
  Object* m_pObject;
};

template<class T>
class SubObject : public Object
{
public:
  virtual SubContainer<SubObject>* GetSubContainer()
  {
    return dynamic_cast<SubContainer<SubObject>*>(GetContainer());
  }

  void TestMe()
  {
    SubContainer<SubObject>* pSubContainer = GetSubContainer();
    assert(pSubContainer);
  }
};

template<class T>
class SubContainer : public Container
{
};


class SubObjectInt : public SubObject<int>
{
};

class SubContainerSubObjectInt : public SubContainer<SubObject<int> > // works
//class SubContainerSubObjectInt : public SubContainer<SubObjectInt> // fails
{
};

测试代码:

SubContainerSubObjectInt* pContainer = new SubContainerSubObjectInt();
SubObjectInt* pObject = new SubObjectInt();

pContainer->SetObject(pObject);

pObject->TestMe();

我知道SubContainer<SubObjectInt>不是SubContainer<SubObject<int> >的子类,即使SubObjectInt是子类SubObject<int>

我标记了代码“工作”和“失败”。说“失败”的行在我的代码中更具逻辑意义,但我无法检索保存它的正确子容器。动态强制转换始终返回NULL。

我的问题是:如何在SubContainer中使用GetSubContainer()检索正确的SubObject

我希望这是有道理的。

2 个答案:

答案 0 :(得分:2)

对代码的最小更改将会改变:

class SubObjectInt : public SubObject<int>
{
};

typedef SubObject<int> SubObjectInt;

当前失败的定义现在将编译并返回一个有效的指针。

如果您希望特定代码特定于与SubObject不同的SubObjectInt,那么您可以改为:

template<class T>
class SubObject : public Object
{
public:
    typedef SubContainer<SubObject<T> > ContainerType;

    ContainerType* GetSubContainer()
    {
        Container* container = GetContainer();
        return dynamic_cast<ContainerType*>(container);
    }

    void TestMe()
    {
        ContainerType* pSubContainer = GetSubContainer();
        assert(pSubContainer);
    }
};

然后你的测试代码看起来像:

SubObjectInt::ContainerType* pContainer = new SubObjectInt::ContainerType();
SubObjectInt* pObject = new SubObjectInt();

pContainer->SetObject(pObject);

pObject->TestMe();

编辑:回应第一条评论

我会说你可能会更好地使用不同的设计,你正在混合继承,组合和模板,使我认为你想要实现的复杂化。

您有一个容器类型,您希望能够分配对象。 你有一个想知道它的容器的对象类型。

您希望容器和对象类型执行相同的操作,并根据内容的不同有所不同。

我会在这些方面提出一些建议:

template<class T>
class ObjectStrategy
{
public:
    virtual void execute(T* object)
    {
        std::cout << "oh noes i am a default general ObjectStrategy" << std::endl;
    }
};

template<class T>
class ContainerStrategy
{
public:
    virtual void execute(T* container)
    {
        std::cout << "oops i am a default general ContainerStrategy" << std::endl;
    }
};

template<class T>
class Object;

template<class T>
class Container
{
public:
    Container() : m_pObject(0), m_strategy(new ContainerStrategy<Container<T> >()) { }
    Container(ContainerStrategy<Container<T> >* strategy_override) : m_pObject(0), m_strategy(strategy_override) { }
    ~Container() { delete m_strategy; }

    void SetObject(T* pObject)
    {
        m_pObject = pObject;
        m_pObject->SetContainer(this);
    }

    void DoContainerStuff()
    {
        m_strategy->execute(this);
    }

protected:
    T* m_pObject;
    ContainerStrategy<Container<T> >* m_strategy;
};

template<class T>
class Object
{
public:
    Object() : m_pContainer(0), m_strategy(new ObjectStrategy<Object<T> >()) { }
    Object(ObjectStrategy<Object<T> >* strategy_override) : m_pContainer(0), m_strategy(strategy_override) { }
    ~Object() { delete m_strategy; }

    Container<Object<T> >* GetContainer()
    {
        return m_pContainer;
    }

    void SetContainer(Container<Object<T> >* pContainer)
    {
        m_pContainer = pContainer;
    }

    void DoObjectStuff()
    {
        m_strategy->execute(this);
    }

    void TestMe()
    {
        DoObjectStuff();
        Container<Object<T> >* pContainer = GetContainer();
        pContainer->DoContainerStuff();
    }
protected:
    Container<Object<T> >* m_pContainer;
    ObjectStrategy<Object<T> >* m_strategy;
};

typedef Object<int> ObjectInt;

template<>
class ObjectStrategy<ObjectInt>
{
public:
    virtual void execute(ObjectInt* container)
    {
        std::cout << "omg i am a default specific strategy for ObjectInt" << std::endl;
    }
};

typedef Container<ObjectInt> ContainerObjectInt;

template<>
class ContainerStrategy<ContainerObjectInt>
{
public:
    virtual void execute(ContainerObjectInt* container)
    {
        std::cout << "pow i am a default specific strategy for ContainerObjectInt" << std::endl;
    }
};

class ObjectIntOverrideStrategy : public ObjectStrategy<ObjectInt>
{
public:
    virtual void execute(ObjectInt* object)
    {
        std::cout << "bam i am an overriding specific strategy for ObjectInt" << std::endl;
    }
};

class ContainerObjectIntOverrideStrategy : public ContainerStrategy<ContainerObjectInt>
{
public:
    virtual void execute(ContainerObjectInt* object)
    {
        std::cout << "woo i am an overriding specific strategy ContainerObjectInt" << std::endl;
    }
};

int main(int argc, char** argv)
{
    {   // test with default + general strategies
        typedef Object<float> ObjectFloat;
        typedef Container<ObjectFloat> ContainerObjectFloat;

        ObjectFloat* pObject = new ObjectFloat();
        ContainerObjectFloat* pContainer = new ContainerObjectFloat();

        pContainer->SetObject(pObject);

        pObject->TestMe();
    }

    {   // test with default + specific strategies
        ObjectInt* pObject = new ObjectInt;
        ContainerObjectInt* pContainer = new ContainerObjectInt;

        pContainer->SetObject(pObject);

        pObject->TestMe();
    }

    {   // test with overriding + specific strategies
        ObjectInt* pObject = new ObjectInt(new ObjectIntOverrideStrategy);
        ContainerObjectInt* pContainer = new ContainerObjectInt(new ContainerObjectIntOverrideStrategy);

        pContainer->SetObject(pObject);

        pObject->TestMe();
    }

    return 0;
}

对象或容器的常用功能分别实现为对象或容器的成员函数。

对象或容器的每种类型功能是通过策略对象的组合实现的,您可以使用工厂根据适当的策略生成适当的对象和容器。

我提出了一种相当灵活的方法(可能过于灵活),因此您可以忽略策略对象的模板特化或继承,具体取决于您需要行为的具体方式。

答案 1 :(得分:0)

你可以尝试一下这个:

class SubObjectInt : public SubObject<int>
{
  public:
  typedef SubObject<int> parent;
};

class SubContainerSubObjectInt 
: virtual public SubContainer<SubObjectInt> 
, virtual public SubContainer<SubObjectInt::parent> 
{
  public:
  void SetObject(Object* pObject)
  {
    SubContainer<SubObjectInt::parent>::SetObject(pObject);
  }
};

为了更清洁,您应该从SubContainer私下继承,并重新发布您作为公共成员所需的实际方法。