Interfaces and covariance problem

前端 未结 5 2040
我在风中等你
我在风中等你 2021-01-05 07:29

I have a particular class that stores a piece of data, which implements an interface:

template
class MyContainer : public Container

        
5条回答
  •  栀梦
    栀梦 (楼主)
    2021-01-05 08:13

    What you are trying to do is called type erasure. Basically you want to provide a value type (which is the same across the whole inheritance hierarchy) that wraps the particular iterator type and offers a uniform dynamic interface.

    Type erasure is usually implemented with a non-virtual class (the type erased) that stores a pointer to a virtual base class that implements the erasure, from which you derive different types that wrap each particular iterator. The static class would offer templated constructor/assignment operators that would dynamically instantiate an object of the derived type and store the pointer internally. Then you only need to implement the set of operations as dispatch to the internal object.

    For the simplest form of type erasure possible, you can take a look at the implementation of boost::any (documentation is here)

    Sketch:

    namespace detail {
       template
       struct any_iterator_base {
          virtual T* operator->() = 0;    // Correct implementation of operator-> is tough!
          virtual T& operator*() = 0;
          virtual any_iterator_base& operator++() = 0;
       };
       template 
       class any_iterator_impl : any_iterator_base {
          Iterator it;
       public:
          any_iterator_impl( Iterator it ) : it(it) {}
          virtual T& operator*() {
             return *it;
          }
          any_iterator_impl& operator++() {
             ++it;
             return *this;
          }
       };
    }
    template 
    class any_iterator {
       detail::any_iterator_base* it;
    public:
       template 
       any_iterator( Iterator it ) : it( new detail::any_iterator_impl(it) ) {}
       ~any_iterator() {
          delete it;
       }
       // implement other constructors, including copy construction
       // implement assignment!!! (Rule of the Three)
       T& operator*() {
          return *it;   // virtual dispatch
       }
    };
    

    The actual implementation becomes really messy. You need to provide different versions of the iterator for the different iterator types in the standard, and the detail of the implementation of the operators might not be trivial either. In particular operator-> is applied iteratively until a raw pointer is obtained, and you want to make sure that your type erased behavior does not break that invariant or document how you break it (i.e. limitations on the type T that your adaptor can wrap)

    For extended reading: - On the Tension Between Object-Oriented and Generic Programming in C++ - any_iterator: Implementing Erasure for C++ iterators - adobe any_iterator ,

提交回复
热议问题