包装器到另一个类继承的模板类

时间:2013-06-13 13:03:04

标签: c++ wrapper

template <class CollectionItem>
class Collection
{
    void A();
    // Many other utility functions
}

class ICollection
{
   virtual void B() = 0;
}


class Base : public Collection<BaseItem>, public IBase
{
    virtual void B();
}

有没有办法通过Collection接口提供ICollection函数而不包含Base类中的所有函数? ICollection : public Collection<CollectionItem>不是一种选择。

赏金更新: 好的,所以最初的想法是拥有所有Collection类的接口。在我们继续之前,每个CollectionItem也有接口,我们称之为ICollectionItemICollection只知道ICollectionItem

所以我做的是创建另一个模板类作为接口到集合模板类 - ICollection(纯虚拟)接受ICollectionItem(s)。 Collection类继承了这个接口。

每个Collection类(继承Collection<CollectionItem>类)也会继承它的接口Collection类。该接口然后虚拟继承ICollection<ICollectionItem>。我只是发布代码:)

以下是代码:

template <class ICollectionItem>
class ICollection
{
public:
    virtual const ICollectionItem* At(const int idx) = 0;
};

template <class CollectionItem, class ICollectionItem>
class Collection
    : public ICollection,
      public virtual ICollection<ICollectionItem>    // Weak point
{
private:
    List<CollectionItem*> fContainer;

public:
    Collection(void) {}
    virtual ~Collection() {}

    virtual const ICollectionItem* At(const int idx);  // Casting GetAt result
    virtual const TCollectionItem& GetAt(const int idx) const 

    virtual ListIterator<TCollectionItem> >* GetIterator(void) const;
    virtual ListIterator<ICollectionItem> >* Iterator(void) const;  // Weak point
}

使用示例:

class IBaseItem
{
public:
    virtual int Number() = 0;
{

class BaseItem
    : public IBaseItem
{
public:
    virtual int Number();
    void SetNumber(int value);
}

class IBase
    : public virtual ICollection<IBaseItem>
{
public:
    virtual IBaseItem* ItemByName(String name) = 0;
    virtual ~IBase() {}
}

class Base
    : public Collection<BaseItem, IBaseItem>,
      public IBase
{
public:
    BaseItem* GetItemByName(String name);
    virtual IBaseItem* ItemByName(String name);
}

弱点:

  • 首先是使用虚拟继承...很多关于它的文章,没什么可说的,或者是它?
  • 无法使用Iterator界面访问ICollection。请参阅ListIterator函数,只能实现第一个,第二个需要某种新的IBaseItem列表。我决定忍受这个,只是用于循环。

    即使我以某种方式设法得到我想要的东西(包装和铸造),我仍然希望听到第二意见。我不喜欢使用虚拟继承,特别是在这种微妙的情况下 - 使用Collections进行应用程序Base创建。

  • 7 个答案:

    答案 0 :(得分:0)

    除了在Collection虚拟方法的Base实现中调用某些IBase方法之外,我看不到任何其他解决方案。

    class Base : public Collection<BaseItem>, public IBase
    {
        virtual void B()
        {
            A();
        }
    }
    

    答案 1 :(得分:0)

    你说,我引用:

      

    我想使用IBase指针调用Collection函数

    除了dynamic_cast之外,我真的不知道要做什么。它完全符合您的要求。

    void fun(IBase * base) {
      auto * coll = dynamic_cast<Collection<BaseItem>*>(base);
      if (coll) {
        coll->A();
      }
    }
    

    您的Collection班级必须拥有虚拟析构函数。

    当然,如果出于某些原因需要不同的基础项目,您可以提供模板化版本。这有很难的代码味道,我认为你的架构在这一点上很糟糕,但是很好。

    template <typename T> void fun(IBase * base) {
       auto * coll = dynamic_cast<Collection<T>*>(base);
       if (coll) {
         coll->A();
       }
     }
    
    void test(IBase * p) {
       fun<BaseItem5>(p);
    }
    

    如果您有其他特定情况编辑您的问题以说明您的意思。

    答案 2 :(得分:0)

    嗯......所以你想重用 Collection 类的实用程序函数,并且你想设计一个实现 IBase 定义的接口的类。如上所述,“将所有函数包装在Base类中”是一种提供Collection函数的方法。

    (1)通过继承,派生类具有集合

    的良好知识
        class Derived:public Collection<DerivedType>,public IBase{};
    

        template <typename T> 
        class Derived:public Collection<T>,public IBase{};
    

    (2)通过继承,派生类对集合知之甚少,但通过 IBase

    class IBase : public Collection<BaseItem>{};
    class Derived:public IBase{};
    

    通过(1),如果要使用 IBase 指针调用Collection函数,则必须包装函数。 通过(2),任何派生实例都是“一种”IBase,它是“一种”集合。因此,您可以使用 IBase 指针来调用Collection函数。


    因此,关键点在于 IBase 指针指向的对象应该具有您要调用的方法。换行它或继承它。除了这两种方式,我看不到任何其他解决方案。

    答案 3 :(得分:0)

    从另一个答案的评论中,您似乎想要一个接口集合,以及此接口的实现。最简单的我可以建议你:

    template<typename T>
    class ICollection
    {
    public:
        virtual iterator<T>* begin() const = 0;
    };
    
    template<typename T, typename TBase>
    class Collection : public ICollection<TBase>
    {
    public:
        iterator_impl<T>* begin() const { return whatever; }
    };
    

    示例:

    class IItem {};
    class Item : public IItem {};
    
    class Base : public Collection<Item, IItem> {};
    
    老答案:

      
        

    有没有办法通过Collection接口提供IBase函数而不包含Base类中的所有函数?

      
         

    如果我理解你的问题,你想这样使用它:

         

    void myfunc()      {          // ...          IBase * obj = ...;          obj-&gt;一种();          obj-&GT; B();      }

         

    我认为这里存在一个误解:如果您希望A()可以IBase调用,则必须将其添加到Ibase声明中。

         

    如果您想在对象上使用Collection函数,那么您应该通过Collection将此对象转换为dynamic_cast

         

    此外,如果你有这样的功能:

         

    虚无趣(IBase * base){/ * ... * /}

         

    无法强制转换为Collection*,因为这两个类之间没有任何关系,除非您有另一种方法可以确保baseCollection }:

         

    虚无趣(IBase * base)      {          if(base&amp;&amp; base-&gt; isABaseItemCollection())          {              //有效,因为以前检查过真实类型              Collection * collection =(Collection *)base;              // ...          }      }

         

    旁注:您几乎可以自动生成基地:

         

    模板      class Base:public Collection,public U {};

         

    typedef Base BaseCollection;

    答案 4 :(得分:0)

    编辑:根据您的示例改进了这个想法: 这是一个想法:

    //generic interface can be kept as it is
    template <class ICollectionItem>
    class ICollection
    {
    public:
        virtual const ICollectionItem*          At(const int idx) = 0;
    };
    class Empty
    {
    };
    
    template <class CollectionItem , class BaseClass = Empty>
    class GenericCollection
        : public BaseClass
    {
    public:
        const CollectionItem*               At(const int idx);  
        // At and ItemByName are standard functions for a collection
        CollectionItem*                     ItemByName(String name);
        //note that here nothing has to be declared as virtual
    };
    
    //example usage:
    
    class IBase
        : public virtual ICollection<IBaseItem>
    {
    public:
        virtual IBaseItem* ItemByName(String name) = 0;
        virtual ~IBase() {}
    };
    
    class Base
        : public GenericCollection<BaseItem, IBase >
    {
    public:
        //nothing to be implemented here, all functions are implemented in GenericCollection and defined as virtual in IBase
        //The definition of the functions has to be the same:
    };
    

    在集合中,您可以实现任何内容,您可以在界面中定义您希望从集合中虚拟的内容。唯一的事情是你需要在函数的命名约定中有一些标准。

    希望这有帮助, Raxvan。

    答案 5 :(得分:0)

    根据评论/聊天:

    你有类似的东西:

    class IAnimal { /*...*/ };
    class Cat : public IAnimal { /*...*/ };
    class Dog : public IAnimal { /*...*/ };
    
    class Cats
    {
        std::vector<Cat*> cats;
    public:
        Cat* at(size_t index) { return cats[index]; }
        /*...*/ 
    };
    
    class Dogs
    {
        std::vector<Dog*> dogs;
    public:
        Dog* at(size_t index) { return dogs[index]; }
        /*...*/
    };
    

    你想用

    之类的东西来分解一些代码
    class IAnimals
    {
    public:
        std::vector<IAnimals*> animals; // or getter/setter which works with IAnimals.
        /* some common factorized code */
    };
    
    // And so
    class Cats : public IAnimals { /**/ };
    class Dogs : public IAnimals { /**/ };
    

    我建议使用模板函数,而不是创建class IAnimals

    template <typename TAnimals>
    void foo(TAnimals& animals)
    {
        Ianimals* animal = animals.at(42);
    
        // ...
        animal->eat(food);
        // ...
    }
    

    您必须为模板中使用的类型提供兼容的“接口”(名称)。

    答案 6 :(得分:-1)

    也许你可以在IBase中有一个operator(),它将被委托给Base?

    class CollectionBase {};
    template <class Item> class Collection: public CollectionBase {};
    
    class IBase
    {
    public:
         virtual CollectionBase* operator()() = 0;
    };
    
    class Base : public Collection<BaseItem>, public IBase
    {
    public:
       virtual Collection<BaseItem>* operator()() { return this; }
    };