2010-10-18 11 views
9

El C++ STL no parece utilizar clases base puramente abstractas (también conocidas como interfaces) con mucha frecuencia. Sé que la mayoría de las cosas se pueden lograr con los algoritmos STL o la metaprogramación de plantillas inteligentes.¿Por qué no hay una interfaz "Iterable" en el STL?

Pero aún así, para algunos casos de uso (por ejemplo, en una API, si no quiero ser específico sobre el tipo de contenedor que obtengo, solo sobre los elementos que contiene), una interfaz de la siguiente forma sea ​​agradable:

template<typename T> struct forward_iterable { 
    struct iterator { 
     typedef T value_type; 
     typedef T& reference; 
     typedef T* pointer; 
     virtual reference operator*() const = 0; 
     virtual pointer operator->() const = 0; 
     virtual bool operator==(const iterator&) const = 0; 
     virtual bool operator!=(const iterator&) const = 0; 
     virtual operator const_iterator() const = 0; 
     virtual iterator& operator++() = 0; 
     virtual iterator operator++(int) = 0; 
    }; 
    struct const_iterator { ... }; // similar, but with const references 

    virtual iterator begin() = 0; 
    virtual const_iterator begin() const = 0; 
    virtual iterator end() = 0; 
    virtual const_iterator end() const = 0; 
}; 

Si los contenedores STL implementar esta clase como función no virtual, esto sería, en mi opinión, no afecta al rendimiento (si uso los contenedores directamente y no a través de esta interfaz). Entonces, ¿por qué hay tan pocas "interfaces" en el STL? ¿O solo estoy pensando demasiado en términos de "Java"?

+0

Hmm, pensé en una complicación: debido a la naturaleza genérica de los operadores de comparación, se requeriría una verificación dinámica de tipo para garantizar que los iteradores sean "compatibles". ¿Es esa la razón por la que no funciona? – summentier

Respuesta

6

STL (que es un subconjunto de la biblioteca estándar) no usa ningún OOP (como en el polimorfismo en tiempo de ejecución) y eso es por diseño.

Con su diseño, ¿no habría problemas para devolver los iteradores por valor (la covarianza no funciona para los tipos de valor)? Es decir, ¿no sería inevitable que todo tuviera que basarse en miembros estáticos (que puede devolver por referencia) o en iteradores asignados en el montón? Esto último parecería bastante extraño en un lenguaje no recogido de basura.

Lo que usted describe (un iterador con plantilla de tipo de valor) se puede lograr mediante una técnica denominada de tipo borrado (y se puede encontrar any_iterator implementaciones por ahí) al igual que function y any tipos de Boost.

La idea básica es:?

//less templated interface 
template <class T> 
class any_iterator_base 
{ 
    virtual void increment() = 0; 
    /*...*/ 
}; 

//derived class templated on iterator type 
template <class Iter, class T> 
class any_iterator_impl: public any_iterator_base<T> 
{ 
    Iter it; 
    virtual void increment() { ++it; } 
    /*...*/ 
}; 

//and a class for the user which makes it all act like a regular value type 
template <class T> 
class any_iterator 
{ 
    shared_ptr<any_iterator_base<T> > it; 
public: 
    template <class Iter> 
    any_iterator(Iter iterator): it(new any_iterator_impl<Iter, T>(iterator)) {} 
    any_iterator& operator++() { it->increment(); return *this; } 
    //... 
}; 

int main() 
{ 
     std::vector<int> vec; 
     any_iterator<int> it = vec.begin(); 
     //... 
} 

puede ser más complicado que eso (por ejemplo, necesidad de hacer algo acerca de la descripción de la categoría y hacer cumplir iterador ?, ¿cómo se comparan dos any_iterators trabajo (doble expedición/RTTI))

2

La razón por la que no se ve una gran cantidad de clases base abstractas estilo "interfaz" en el STL se debe a que se basa tanto en las plantillas C++. Cuando utiliza plantillas C++, prácticamente cualquier clase, sea cual sea su origen, funcionará siempre que admita todos los métodos que la plantilla intenta usar.

Hay una especie de interfaz implícita, pero en realidad escribirla es irrelevante. En mi propia codificación, tiendo a escribir uno de todos modos, como una conveniencia para el usuario, pero esa no es la forma en que los escritores STL ruedan.

0

Las estructuras STL no se definen teniendo en cuenta la herencia. No es fácil hacer un buen caso para subclasificar cualquiera de las colecciones stl. Con esto en mente, el stl no le hace "pagar" ningún costo que pueda haber estado asociado con la herencia de clase normal. Si se usaran métodos virtuales, el optimizador no podría incluirlos.

Además, STL desea ser compatible con cosas que posiblemente no podrían heredar de una clase base abstracta de primer nivel, como matrices.

+0

Creo que las especializaciones no virtuales de métodos virtuales pueden incluirse si se llama directamente al método de la subclase (y no a través de la clase base), por lo que agregar interfaces solo agregaría penalizaciones de rendimiento cuando sea necesario. – summentier

Cuestiones relacionadas