c++ - standard - librerias turbo c
Interfaz/Superclase para Colecciones/Contenedores en c++ (4)
De su descripción, creo que la respuesta corta es no.
En general, cuando estoy creando algún tipo de colección como esta normalmente usaría un typedef para especificar el contenedor que estoy usando:
class Object {
typedef std::list<int> Cont;
typedef Cont::iterator iterator;
typedef Cont::const_iterator const_iterator;
// ....
};
Todo el código del cliente se refiere a "Object :: Cont", etc., y siempre que los clientes solo utilicen las características generales de los contenedores, no necesitarán cambiar si el contenedor cambia.
Si no puede cambiar su API ahora, entonces creo que su solución es bastante buena, sin embargo, dependiendo de la información que tenga, si hace muchas inserciones que tienden a ser únicas, entonces puede ser más eficiente continuar usando el lista y solo elimina duplicados al final:
void foo (std::list<int> & list) {
// ... fill the list
list.sort ();
list.unique ();
}
Vengo del mundo de Java y estoy construyendo un pequeño programa de c ++ en este momento. Tengo un objeto que hace algún trabajo y luego devuelve el resultado del trabajo como una lista.
Ahora, un día después, cambié el comportamiento del objeto para guardar los resultados en un conjunto para evitar duplicados en el contenedor. Pero no puedo simplemente devolver el conjunto porque utilicé una lista para la interfaz la primera vez. ¿Existe una interfaz de contenedor común que pueda usar para especificar la interfaz de mi objeto y olvidarme del tipo de contenedor que uso internamente?
En este momento estoy creando un conjunto agregando todos los valores y luego creando una lista del conjunto:
return std::list<foo>(this->mySet.begin(), this->mySet.end())
Parece un poco extraño.
El concepto de contenedor está engendrado por iteradores.
Como has visto, la codificación dura de un tipo específico de contenedor probablemente no sea lo que deseas. Entonces haz que tu clase devuelva iteradores. Luego puede reutilizar los iteradores de conatiners.
class MyClass
{
private:
typedef std::list<int> Container;
public:
typedef Container::iterator iterator;
typedef Container::const_iterator const_iterator;
iterator begin() {return myData.begin();}
const_iterator begin() const {return myData.begin();}
iterator end() {return myData.end();}
const_iterator end() const {return myData.end();}
private:
Container myData;
};
Ahora cuando cambia el tipo de contenedor de std :: list a std :: set, nadie necesita saber.
Además, al usar los nombres estándar que utilizan otros contenedores, su clase comienza a verse como cualquier otro contenedor del STL.
Nota: Un método que devuelve un const_iterator debe ser un método const.
No existe interfaz En cambio, normalmente usaría plantillas, y simplemente diría "No me importa de qué tipo es, siempre que se comporte como un contenedor".
Suponiendo que tu función se ve así:
std::list<int> DoStuff()
se puede llamar así:
template <typename container_type>
void caller() {
container_type result = DoStuff();
}
Solo la primera función debe cambiarse si decide devolver un set
. La función de llamada realmente no le importa (siempre y cuando no confíe en los detalles de una lista, por supuesto).
Si publica un poco más de código de muestra, podríamos estar en mejores condiciones para sugerir cómo debería hacerse en C ++.
Toda la biblioteca estándar de C ++, incluidos sus contenedores, a diferencia de Java, no es una interfaz (herencia, polimorfismo), sino que está basada en plantillas (por razones de eficacia).
Puede crear un contenedor polimórfico alrededor de su colección, pero esta no es la forma C ++.
La solución más simple es simplemente simplificar el programa con algunos alias de tipo:
#include <iostream>
#include <list>
#include <vector>
using namespace std;
class Test {
private:
typedef vector<int> Collection;
Collection c;
public:
typedef Collection::const_iterator It;
void insert(int Item) {
c.push_back(Item);
}
It begin() const { return c.begin(); }
It end() const { return c.end(); }
};
int main() {
Test foo;
foo.insert(23);
foo.insert(40);
for (Test::It i = foo.begin(); i != foo.end(); ++i)
cout << *i << endl;
return 0;
}
Ahora puede cambiar Collection
-typedef sin tener que cambiar nada más. (Nota: si haces que la Collection
pública, el usuario podrá referir el tipo que usaste explícitamente)