0
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 类提供接口。在我们继续之前,everyCollectionItem也有接口,我们称之为它ICollectionItem并且ICollection只知道ICollectionItem.

所以我所做的就是创建另一个模板类作为 Collection 模板类的 Interface - ICollection(pure virtual) accepting ICollectionItem(s)。Collection 类继承了这个接口。

每个Collection类(继承Collection<CollectionItem>类)也将继承它的接口Collection类。该接口然后 virtual 继承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功能,只能实现第一个,第二个需要某种新的 List IBaseItem。我决定接受它,只使用 for 循环。

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

  • 4

    7 回答 7

    0

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

    class Base : public Collection<BaseItem>, public IBase
    {
        virtual void B()
        {
            A();
        }
    }
    
    于 2013-06-13T13:10:11.200 回答
    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);
        // ...
    }
    

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

    于 2013-10-14T12:39:53.920 回答
    0

    嗯...所以您想重用Collection类的实用功能,并且您想设计一个将实现IBase定义的接口的类。正如您上面提到的,“将所有函数包装在基类中”是提供集合函数的一种方式。

    (1)通过继承,派生类对Collection有很好的了解

        class Derived:public Collection<DerivedType>,public IBase{};
    

    或者

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

    (2)通过继承,派生类对Collection知之甚少 ,而是通过IBase

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

    通过(1),如果你想使用IBase指针调用 Collection 函数,你必须包装函数。通过(2),任何Derived实例都是“一种”IBase,即“一种”集合。所以你可以使用IBase指针来调用 Collection 函数。


    所以,关键是IBase指针指向的对象应该有你要调用的方法。包装它或继承它。除了这两种方式,我看不到任何其他解决方案。

    于 2013-10-08T11:53:43.130 回答
    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);
    }
    

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

    于 2013-10-07T21:31:11.970 回答
    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->A(); obj->B(); }

    我认为这里有一个误解:如果你想A()从 an 中调用IBase,那么你必须将它添加到Ibase声明中。

    如果要Collection在对象上使用函数,则应将此对象强制转换为 a ,例如Collectionvia 。dynamic_cast

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

    void fun(IBase* base) { /* ... */ }

    不能转换为 a Collection*,因为这两个类之间没有关系,除非您有另一种方法可以确定basea Collection

    void fun(IBase* base) { if(base && base->isABaseItemCollection()) { // 有效,因为在 Collection* collection = (Collection*)base; // ... } }

    附带说明:您几乎可以自动生成碱基:

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

    typedef Base BaseCollection;

    于 2013-10-09T12:56:02.930 回答
    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:
    };
    

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

    希望这会有所帮助,拉克斯万。

    于 2013-10-09T13:00:58.483 回答
    -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; }
    };
    
    于 2013-06-13T13:10:47.517 回答