Pregunta

Considere 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 funcionar BaseFoo, pero el compilador no me deja.¿Cómo soluciono esto, sin copiar todo el vector a un std::vector<Base*>?

¿Fue útil?

Solución

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

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

Además, para evitar copiar el vector innecesariamente, debes pasarlo por referencia constante, no por valor:

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

Finalmente, para evitar pérdidas 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 contener 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, deberá modificar su BaseFoo funcionar en consecuencia.

Otros consejos

En lugar de pasar el objeto contenedor (vector<>), Aconteció en begin y end iteradores como el resto de algoritmos STL.La función que los recibe tendrá una plantilla y no importará si pasa Derivado* o Base*.

Este problema ocurre en lenguajes de programación que tienen contenedores mutables.No se puede hacer pasar una bolsa de manzanas mutable como una bolsa de fruta porque no se puede estar seguro de que alguien más 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.Búsqueda de covarianza/contravarianza.

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 pequeño exceso de código.Terminará con diferentes funciones instanciadas para cada tipo, pero el código sigue siendo el mismo.Dependiendo del caso de uso, es una solución rápida y sucia.

Editar, debo señalar que la razón por la que necesitamos una plantilla aquí es porque estamos tratando de escribir el mismo código para tipos no relacionados, como lo señalaron varios otros carteles.Las plantillas le permiten resolver estos problemas exactos.También lo actualicé para usar una referencia constante.También debes pasar objetos "pesados" como un vector por referencia constante cuando no necesites una copia, lo cual es básicamente siempre.

Generalmente se comenzaría con un contenedor de punteros base, y no al revés.

Tomando matt precio Responda desde arriba, dado que 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 );

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, corrija su código con una de las otras sugerencias.

Si std::vector admitió lo que estás pidiendo, entonces sería posible derrotar el sistema de tipo C++ sin usar ninguna conversión (editar: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!

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

Soporte de matrices Java subtipo covariante, y esto requiere que Java haga una verificación del tipo de tiempo de ejecución cada vez que almacene un valor en una matriz.Esto también es indeseable.

Son tipos no relacionados, no se puede.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top