vectores una terminos respecto representacion relativas matriz escribir escriba dada coordenadas cambio c++ stl vector covariance

c++ - terminos - Obteniendo un vector<Derived*> en una función que espera un vector<Base*>



matriz cambio de base (9)

En general, comenzaría con un contenedor de punteros base, no a la inversa.

Considera estas clases.

class Base { ... }; class Derived : public Base { ... };

esta función

void BaseFoo( std::vector<Base*>vec ) { ... }

Y finalmente mi vector

std::vector<Derived*>derived;

Quiero pasar derived a la función BaseFoo , pero el compilador no me deja. ¿Cómo resuelvo esto, sin copiar todo el vector en un std::vector<Base*> ?


En lugar de pasar el objeto contenedor ( vector<> ), pase iteradores de begin y end como el resto de los algoritmos STL. La función que los recibe se modelará y no importará si pasa Derived * o Base *.


Este problema ocurre en lenguajes de programación que tienen contenedores mutables. No puede pasar una bolsa mutable de manzanas como una bolsa de fruta porque no puede estar seguro de que otra persona no ponga un limón en esa bolsa de fruta, después de lo cual ya no califica como una bolsa de manzanas. Si la bolsa de manzanas no fuera mutable, pasarla como una bolsa de fruta estaría bien. Buscar covarianza / contravariancia.


No son tipos relacionados, no puedes.


Si std::vector compatible con lo que está pidiendo, entonces sería posible vencer el sistema de tipo C ++ sin usar ningún molde (edite el enlace de ChrisN a C ++ FAQ Lite habla sobre el mismo problema):

class Base {}; class Derived1 : public Base {}; class Derived2 : public Base {}; void pushStuff(std::vector<Base*>& vec) { vec.push_back(new Derived2); vec.push_back(new Base); } ... std::vector<Derived1*> vec; pushStuff(vec); // Not legal // Now vec contains a Derived2 and a Base!

Como su función BaseFoo() toma el vector por valor, no puede modificar el vector original que pasó, por lo que lo que escribí no sería posible. Pero si toma una referencia no constante y utiliza reinterpret_cast<std::vector<Base*>&>() para pasar su std::vector<Derived*> , es posible que no obtenga el resultado que desea, y su programa puede bloquearse.

Las matrices Java admiten la subtipificación covariante , y esto requiere que Java haga una comprobación de tipo de tiempo de ejecución cada vez que almacene un valor en una matriz . Esto también es indeseable.


Si se trata de una biblioteca de terceros, y esta es su única esperanza, puede hacer esto:

BaseFoo (*reinterpret_cast<std::vector<Base *> *>(&derived));

De lo contrario, corrige tu código con una de las otras sugerencias.


Tomando la respuesta de Matt Price de arriba, dado que usted sabe de antemano qué tipos desea usar con su función, puede declarar la plantilla de función en el archivo de encabezado y luego agregar instancias explícitas para esos tipos:

// BaseFoo.h template<typename T> void BaseFoo( const std::vector<T*>& vec); // BaseFoo.cpp template<typename T> void BaseFoo( const std::vector<T*>& vec); { ... } // Explicit instantiation means no need for definition in the header file. template void BaseFoo<Base> ( const std::vector<Base*>& vec ); template void BaseFoo<Derived> ( const std::vector<Derived*>& vec );


una opción es usar una plantilla

template<typename T> void BaseFoo( const std::vector<T*>& vec) { ... }

El inconveniente es que la implementación tiene que estar en el encabezado y obtendrás un poco de código inflado. Concluirá con diferentes funciones que se instanciarán para cada tipo, pero el código permanece igual. Dependiendo del caso de uso, es una solución rápida y sucia.

Editar, debería tener en cuenta que la razón por la que necesitamos una plantilla aquí es porque estamos tratando de escribir el mismo código para los tipos no relacionados, como lo señalan otros carteles. Las plantillas le permiten resolver estos problemas exactos. También lo actualicé para usar una referencia constante. También debe pasar objetos "pesados" como un vector por referencia constante cuando no necesite una copia, que es básicamente siempre.


vector<Base*> y vector<Derived*> son tipos no relacionados, por lo que no puede hacer esto. Esto se explica en las preguntas frecuentes de C ++ here .

Puede cambiar su variable de un vector<Derived*> a un vector<Base*> e insertar objetos Derived en él.

Además, debe pasar el vector por const-reference, no por valor:

void BaseFoo( const std::vector<Base*>& vec ) { ... }

Finalmente, para evitar fugas de memoria y hacer que su código sea seguro para excepciones, considere usar un contenedor diseñado para manejar objetos asignados en el montón, por ejemplo:

#include <boost/ptr_container/ptr_vector.hpp> boost::ptr_vector<Base> vec;

Alternativamente, cambie el vector para mantener un puntero inteligente en lugar de usar punteros sin formato:

#include <memory> std::vector< std::shared_ptr<Base*> > vec;

o

#include <boost/shared_ptr.hpp> std::vector< boost::shared_ptr<Base*> > vec;

En cada caso, necesitaría modificar su función BaseFoo según corresponda.