2009-09-03 10 views
5

Hey, en C++, I tienen un vector de tipo:vector iteradores de reparto

vector<BaseClass*> myVector; 

En la que, I inserto (push_back) punteros de clases derivadas en ella.

Ahora, yo quiero a pop volver sus elementos por lo que hago esto:

vector<ADlgcDev*>::iterator iter; 

for (iter = myVector.rbegin(); iter != myVector.rend(); iter++) 
{ 
// but before I pop it, I need to shutdown it down 
// so I cast this 
// but this way, I'm unable to call the function 
(DerivedClass*(*iter))->Shutdown(); 

myVector.pop_back(); 
} 

sino como una mención en los comentarios antes de que el pop, necesito llamar a su apagado() método y el reparto no funciona correctamente también ¿Alguna resolución? o es imposible?

+3

Por cierto, su bucle está roto - deje su bucle 'for' sin cambios y elimine' myVector.pop_back() ', o deje eso en y cambie a un bucle' while' que examine el elemento 'back()' cada vez que sbi sugiere. –

+0

¿Cómo se rompe mi lazo? – akif

+1

Si realiza mentalmente los pasos con una matriz de 10 elementos, encontrará que solo procesa los primeros 5, porque para ese momento ya ha eliminado los últimos 5 con 'pop_back()'. –

Respuesta

13
while (!myVector.empty()) 
{ 
    ((DerivedClass*)(myVector.back()))->Shutdown(); 
    myVector.pop_back(); 
} 

Notas:

  • Probablemente debería utilizar dynamic_cast en lugar de la fundición dura. (Si está seguro de que solo hay DerivedClass objetos en el vector, ¿por qué no es std::vector<DerivedClass>?)
  • Probablemente no deba tener que lanzar nada, ya que Shutdown() debe declararse en la clase base.
  • Probablemente también deba eliminar los objetos, antes de que se salgan del vector. (Pero puede que no sea así.)
  • Probablemente deba utilizar un puntero inteligente que llame al Shutdown() (y delete, probablemente).

Editar: Usando std::vector<T>::clear(), as shown by markh44 es probablemente mejor que la pop_back().

+0

Excelente consejo, especialmente viñeta # 2. Pero stefaanv tiene razón, los moldes de estilo constructor no funcionarán para los tipos de punteros, haga lo que sugiere en su lugar. –

+0

Me acuerdo con los comentarios y me gusta el nuevo bucle – stefaanv

+0

Incluso mejor - deshacerse de 'apagado()' por completo y poner la funcionalidad en el destructor (que debe convertirse en 'virtual' ya que va a eliminar una clase derivada a través un puntero de clase base). Utilizar un 'vector >' en lugar, y entonces no se necesita recordar hacer nada *! * –

1

La conversión del constructor no funciona para los punteros. Utiliza static_cast si estás seguro o dynamic_cast y comprueba.

-1

Si Shutdown() es un método virtual de la clase Base, es decir, BaseClass :: ShutDown() debe llamar directamente a iter-> ShutDown();

De lo contrario, si el método no es virtual, debe usar dynamic_cast.

vector<ADlgcDev*>::iterator iter; 

for (iter = myVector.rbegin(); iter != myVector.end(); iter++) 
{ 
DerivedClassA* a = dynamic_cast<DerivedClassA*>(*iter) ; 
if (a) a->ShutDownA(); 
else 
{ 
DerivedClassB* b = dynamic_cast<DerivedClassB*>(*iter); 
if (b) b->ShutDownB(); 
// ... repeat for every class in hierarchy that might be in the vector. 
} 
myVector.pop_back(); 
} 

De todos modos es probable que se escapa de la memoria, a no ser apagado() elimina el objeto de la misma (que es generalmente una mala idea) o que está manteniendo punteros duplicados y eliminarlos en otro lugar, lo que es otra idea arriesgada.

+0

¿Usted ha visto lo que es 'iter'. inicializado con y en qué se compara? ¿Y cuál escogerías para que 'myVector.pop_back()' no cause estragos en el iterador? Y si hay _several_ clases derivadas que tienen una función 'ShutDownX()', probablemente _debe ser una función virtual declarada en la clase base. – sbi

+0

Estaba haciendo los cambios mínimos en su diseño. Por supuesto, debería derivarse, y todo el ciclo podría escribirse en dos líneas. – davidnr

2

¿Podría hacer de Shutdown una función virtual en BaseClass? Entonces no necesitarías un elenco.

También es probable que tenga problemas para eliminar elementos de un vector mientras itera. Yo lo haría así:

vector<BaseClass*>::iterator iter; 

for (iter = myVector.rbegin(); iter != myVector.rend(); iter++) 
{ 
    (*iter)->Shutdown(); 
} 
myVector.clear(); 

Editar: y otra cosa, ++ iter se prefiere generalmente durante ++ ITER.

+0

Supongo que 'rbegin()' vs. 'end()' también podría dar problemas. Sin embargo, usar 'clear()' es una muy buena idea. – sbi

+0

@sbi meh, ¿cómo llegó eso? Estoy seguro de que puedo copiar y pegar ese código ... – markh44

+0

@ markh44: Ese es el problema. Fue uno de los problemas con el código original. – sbi

Cuestiones relacionadas