简体   繁体   English

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

[英]wrapper to template class inherited by another class

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();
}

Is there any way of offering Collection functions via ICollection interface without wrapping all the functions in Base class? 是否可以通过ICollection接口提供Collection函数而无需将所有函数包装在Base类中? ICollection : public Collection<CollectionItem> is not an option. ICollection : public Collection<CollectionItem>不是一个选项。

Bounty Update: OK, so the original idea was to have Interface to all Collection classes. 赏金更新:好的,所以最初的想法是为所有Collection类提供接口。 Before we continue, every CollectionItem also has Interface, let's call it ICollectionItem and ICollection only knows about ICollectionItem . 在继续之前,每个CollectionItem还具有接口,我们将其称为ICollectionItemICollection仅知道ICollectionItem

So what I did was create another template class as Interface to Collection template class - ICollection (pure virtual) accepting ICollectionItem(s) . 因此,我要做的是创建另一个模板类作为与Collection模板类的接口ICollection (纯虚拟)接受ICollectionItem(s) Collection class inherits this interface. 集合类继承了此接口。

Every Collection class (inheriting Collection<CollectionItem> class) would also inherit it's Interface Collection class. 每个Collection类(继承Collection<CollectionItem>类)也将继承其Interface Collection类。 That Interface then virtual inherits ICollection<ICollectionItem> . 然后,该接口虚拟继承ICollection<ICollectionItem> I'll just post the code :) 我将发布代码:)

Here is the code: 这是代码:

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
}

Example usage: 用法示例:

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);
}

Weak points: 弱点:

  • First is at using virtual inheritance ... lots written about it, not much to talk about, or is it? 首先是使用虚拟继承。关于虚拟继承的文章很多,没有太多要谈论的,或者是吗?
  • Unable to access Iterator using ICollection interface. 无法使用ICollection接口访问Iterator See ListIterator function, only first one can be implemented, the second one would require some kind of new List of IBaseItem . 请参见ListIterator函数,只能实现第一个,第二个需要某种新的IBaseItem List。 I decided to live with that and just use for loop. 我决定忍受这个,只使用for循环。

    Even tho I somehow managed to get what I wanted (With wrapping and casting), I would still like to hear an second opinion. 即使我以某种方式设法获得了想要的东西(通过包装和浇铸),我仍然想听听第二意见。 I don't like using virtual inheritance, specially in such delicate situations - using Collections for application Base creation. 我不喜欢使用虚拟继承,特别是在这种微妙的情况下-使用Collections创建应用程序库。

  • I can not see any other solution than calling some Collection method in Base implementation of IBase virtual methods. 除了在IBase虚拟方法的Base实现中调用某些Collection方法之外,我看不到任何其他解决方案。

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

    You say, and I quote: 你说,我引用:

    I want to call Collection functions using IBase pointer 我想使用IBase指针调用Collection函数

    I really don't see what is to be done here besides dynamic_cast . 除了dynamic_cast我真的看不到该做什么。 It does exactly what you want it to do. 它确实可以满足您的要求。

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

    Your Collection class must have a virtual destructor. 您的Collection必须具有虚拟析构函数。

    You can, of course, offer a templated version, if you'd need different baseitems in different, scenarios for some reasons. 当然,如果出于某些原因在不同的场景中需要不同的基本项目,则可以提供模板版本。 This has bad code smell and I think your architecture is bad at this point, but oh well. 这有不好的代码味道,我认为您的架构在这一点上很糟糕,但是很好。

    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);
    }
    

    If you have some other specific scenario in mind , please edit your question to say what you mean. 如果您有其他特定情况编辑您的问题以说出您的意思。

    Hmm...So you wanna to reuse the Collection class's utility functions, and you want to design a class which will implement an interface defined by IBase . 嗯...所以您想重用Collection类的实用程序功能,并且想要设计一个将实现IBase定义的接口的类。 As you mentioned above,"wrapping all the functions in Base class" is a way to offer Collection functions. 如上所述,“包装基类中的所有函数”是提供Collection函数的一种方式。

    (1) Via inheritance,derived class has a good knowledge of Collection (1)通过继承,派生类对Collection有很好的认识

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

    or 要么

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

    (2) Via inheritance,derived class knows little about Collection ,but through IBase (2)通过继承,派生类对Collection知之甚少,但通过IBase

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

    By (1),If you want to call Collection functions using IBase pointer,you have to wrap the functions. 通过(1),如果要使用IBase指针调用Collection函数,则必须包装这些函数。 By (2), any Derived instance is " a kind of " IBase which is "a kind of " Collection. 通过(2),任何派生实例都是“一种”的IBase,它是“一种”的Collection。 So you can use IBase pointer to call Collection functions. 因此,您可以使用IBase指针来调用Collection函数。


    So,the key point is that the objects pointed by the IBase pointer should have the method you want to call. 因此,关键是IBase指针所指向的对象应该具有您要调用的方法。 Wrap it or inherit it. 包装继承它。 I can not see any other solution than these two ways. 除了这两种方式,我看不到任何其他解决方案。

    From your comments in another answer, it seems you want a collection of interfaces, and an implementation of this interface. 从另一个答案中的注释看来,您似乎想要接口的集合以及该接口的实现。 The simplest I can advise you is the following: 我可以建议您的最简单的方法如下:

    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; }
    };
    

    Example: 例:

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

    old answer: 旧答案:

    Is there any way of offering Collection functions via IBase interface without wrapping all the functions in Base class ? 是否可以通过IBase接口提供Collection函数而无需将所有函数包装在Base类中?

    If I understood your problem, you want to use it like this: 如果我了解您的问题,则想像这样使用它:

    void myfunc() { // ... IBase* obj = ...; void myfunc(){// ... IBase * obj = ...; obj->A(); obj-> A(); obj->B(); obj-> B(); } }

    I think here is a misunderstanding here: if you want A() to be callable from an IBase , then you have to add it to Ibase declaration. 我认为这是一个误解:如果您希望A()可从IBase调用,则必须将其添加到Ibase声明中。

    If you want to use the Collection functions on an object, then you should cast this object to a Collection , via dynamic_cast for example. 如果要在对象上使用Collection函数,则应将此对象通过dynamic_castCollection

    Furthermore, if you have such a funcion: 此外,如果您有这样的功能:

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

    you cannot cast to a Collection* , since there are no relationship between these two classes, unless you have another way to be sure base is a Collection : 不能转换为Collection* ,因为这两个类之间没有关系,除非您有另一种方法来确保baseCollection

    void fun(IBase* base) { if(base && base->isABaseItemCollection()) { // Valid, since the real type was checked before Collection* collection = (Collection*)base; void fun(IBase * base){if(base && base-> isABaseItemCollection()){//有效,因为在Collection * collection =(Collection *)base之前检查了实类型; // ... } } // ...}}

    On a side note: you can generate bases almost automatically: 附带说明:您几乎可以自动生成基准:

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

    typedef Base BaseCollection; typedef Base BaseCollection;

    Edit: the idea is refined based on your example: Here is an idea: 编辑:根据您的示例精炼此想法:这是一个想法:

    //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:
    };
    

    In collection you can implement whatever and in the interface you can define what ever you want to be virtual from your collection. 在集合中,您可以实施任何操作,并且在界面中可以定义要从集合中虚拟化的任何内容。 The only thing is that you need to have some standard in naming convention for functions. 唯一的事情是您需要对函数的命名约定有一些标准。

    Hope this helps, Raxvan. 希望这会有所帮助,Raxvan。

    According to comment/chat: 根据评论/聊天:

    You have something like: 你有类似的东西:

    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]; }
        /*...*/
    };
    

    And you want to factorize some code using something like 而且您想使用类似

    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 { /**/ };
    

    I propose, instead of creating class IAnimals , to use template functions as: 我建议不要创建class IAnimals ,而将模板函数用作:

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

    You have to give compatible "interface" (names) to the type used in template. 您必须为模板中使用的类型提供兼容的“接口”(名称)。

    Maybe you could have an operator() in IBase that would be delegated to Base? 也许您可以在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; }
    };
    

    声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

     
    粤ICP备18138465号  © 2020-2024 STACKOOM.COM