Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





C++

Iniciado por Pogacha, 21 de Abril de 2005, 06:53:19 PM

« anterior - próximo »

Pogacha

 Que tal ...
Esta es una duda que siempre tuve y me gustaria ver si alguien me la aclara...

Si tengo

class a
{
 private:
   friend class Generadora_De_a;
    virtual a()
public:  
   virtual ~a();
   virtual foo();
};


class b : public a
{
 private:
   friend class Generadora_De_a;
    b()
public:  
   ~b();
    foo();
};

class c : public a
{
 private:
   friend class Generadora_De_a;
    virtual c()
public:  
   virtual ~c();
   virtual foo();
};


Que pasa, suponiendo que b no hereda mas, ni tampoco c, y que solo uso (en ejemplo):
a* o  = Generadora_De_a->Crear_a_b_o_c();  
a->foo();
delete a;


¿cual es mejor? ... ¿que diferencias habra?,¿como maneja esto el compilador ?... ¿no le da importancia ?

Saludos

_Grey

 Pues no se, que se supone que tiene que pasar.....?

Creo que no entiendo muy bien la pregunta, pero me arriesgare, teniendo el codigo:

a* o  = Generadora_De_a->Crear_a_b_o_c();  
a->foo();
delete a;


Que tu has puesto; si Generadora_De_a->Crear_a_b_o_c() a creado una clase de tipo c se llamara a foo de la clase c, si la que se creo es de tipo b, se llamara a foo de la clase b, y si es de tipo a al foo de la clase a.
Con el destructor pasara igual por que el de la clase a es virtual.

Es esto??? o nop?!

Saludos.

[EDIT]

ATENCION!!!

El constructor no puee ser virtual..... un poquito de por favor hombre......

Casi se me pasa....

senior wapo

 Asumo que estás creando un objeto a/b/c pero devolviéndolo siempre como si fuese 'a' a base de casts feos y malintencionados.

Ocurrirá que se ejecutará la función foo() de la clase a,b o c aunque estés llamándola como a->foo(). La razón es que a nivel ABI (representación binaria) todos tienen vftable y su vftable tiene el mismo orden y tamaño. El codigo será 0% portable porque no está definido por ningún standard, y simplemente ocurre que casualmente coincide así en la implementación.

Es una guarreria como una casa, pero eso ya lo sabias tu :)

Otra cosa, el delete puede corromper el heap/pila ya que se libera un bloque de x bytes (sizeof de la clase a) y realmente puede ser de un tamaño distinto (sizeof de las otras clases, que en teoría debería ser el mismo en ese ejemplo, pero vete a saber...). Dependiendo de la implementación del gestor de memoria  y de la estrategia de asignación que haya usado el compilador (optimizar el new inline  usando el stack si detecta que puede colar),  pueden pasar cosas muy muy feas.

Pogacha

 He concluido que me expreso realmente mal ... preste toda la atención que pude en hacer la pregunta y aun así dije cualquier cosa ...

Lo de los constructores virtuales si, se me pasaron  (nooo)
Tambien me falle en un o por a y el casting
a* o  = Generadora_De_a->Crear_a_b_o_c();
o->foo();
delete o;


Reformulo la pregunta:
b no tiene declaradas sus miembros como virtuales, pero c si los tiene ... ¿ que significado puede tener esto ?

Segun mi entender el keyword virtual solo modificara a futuras herencias ... pero por ejemplo:

class d : public b // que no era virtual
{
public:  
 virtual  foo();
};

class e : public d // que era virtual
{
public:
  foo();
};


que funcion se llama entonces en :
o = new d;
((a*)o)->foo();

y aquí:o = new e;
((a*)o)->foo();


Citarel delete puede corromper el heap/pila ya que se libera un bloque de x bytes (sizeof de la clase a)
Esto no lo habia pensado pero me parece que no puede ser así, el destructor es virtual (es como llamar a free(), que new y delete caen en malloc y free dicho sea de paso), en cualquier caso el inline new/delete es problema del compilador no mio.

Saludos

_Grey

 
Citarb no tiene declaradas sus miembros como virtuales, pero c si los tiene ... ¿ que significado puede tener esto ?

El destructor y la función foo() de b son virtuales, aun que no lo indiques; por que?? por que en la clase base a, lo son. De hecho es recomendable indicarlo para facilitar la legibilidad del código, pero aun no indicándolo lo son, por que "heredan" ese comportamiento. Son virtuales como en c.

que función se llama entonces en :
CODE
o = new d;
((a*)o)->foo();

y aquí:
CODE
o = new e;
((a*)o)->foo();


Esta es mas difícil, puede que me equivoque.
Se llamara al foo() de d, en el primer caso, y al foo() de e en el segundo.
Y tengo que recalcar que el foo() de e, es una función virtual como en d por que "hereda" ese comportamiento aun y cuando no lo indiques, por que en la clase base es virtual, creo que es aquí donde esta tu duda, verdad?? ;)

Espero que te sirva, saludos.

Pogacha

 
CitarY tengo que recalcar que el foo() de e, es una función virtual como en d por que "hereda" ese comportamiento aun y cuando no lo indiques, por que en la clase base es virtual, creo que es aquí donde esta tu duda, verdad??
(ole), asi que el virtual se hereda, ahora todo tiene sentido, pero me queda la duda, aun que casi seguro que:

o = new e;
((d*)o)->foo();

Llama a d->foo();
pero tendria que probarlo ...

Saludos y muchas gracias ...

_Grey

 
Citarpero me queda la duda, aun que casi seguro que:

CODE
o = new e;
((d*)o)->foo();

Llama a d->foo();
pero tendria que probarlo ...

llama al de e por que es una funcion virtual heredada de d...nop? :huh:  

nsL

 Joer que embrollo, es como el examen de la uni de POO, que te metian ahi 3 clases, q se heredaban entre ellas, con metodos virtuales y te decian al final: se puede hacer esto? y te metian una sentencia rarisima q implicaba a un metodo q estaba heredado pero q no se que .... bla bla

Realmente tienes un problema q requiera hacer tanto lio? o simplemente porq querias saber como es o si es posible?, es que yo hasta ahora no se me ha complicado tanto la vida programando :P

Saludos!  B)
Yo no muero hasta la muerte -

Pogacha

 
CitarEscrito el 21/04/05, 18:22
--------------------------------------------------------------------------------
QUOTE 
pero me queda la duda, aun que casi seguro que:

CODE
o = new e;
((d*)o)->foo();

Llama a d->foo();
pero tendria que probarlo ...


llama al de e por que es una funcion virtual heredada de d...nop? 
En realidad llama a la de d por que d->foo() no es virtual ... si pusiera ((a*)o)->foo(); deberia llamara al de e, pero todo esto tengo que probarlo y aqui no tengo un compilador ... mañana te cuento...

CitarRealmente tienes un problema q requiera hacer tanto lio? o simplemente porq querias saber como es o si es posible?, es que yo hasta ahora no se me ha complicado tanto la vida programando
Las dos cosas, tengo una clase Objeto; de ahí heredo por un lado Objeto_Fisico, despues Elipsoide_Movil, despues Personaje_Principal ... y quiero saber que si tengo que declarar como virtuales las funciones de cada clase o solo las de la bases ... funcionar funciona, pero no se que que estará pasando realmente pues puede colgarse y no sabre por que, debo estar seguro de las cosas ...

Saludos

zupervaca

 yo tengo la costumbre que por legibilidad del codigo y asi poder ver rapidamente que se esta haciendo poner virtual a las funciones que sean virtuales en su clase base, tambien soy de los que piensan que las funciones que realizan operaciones no deberian ser virtuales si no que habria que hacer eventos para evitar problemas como: ¿llamo al inicio de la funcion a la clase base o al final?

por mi experiencia en equipos de desarrollo de aplicaciones grandes siempre es recomendable crear eventos virtuales (puros o no)

ejemplo por si no me explico bien:

class a
{
bool inicializa();
virtual bool onpreinicializa();
virtual bool oninicializa();
};

inicializa llamaria en el momento correcto a oninicializa, el otro evento onpreinicializa serviria para realizar operaciones antes de que se inicialice, etc
de esta forma el programador esta seguro de que la funcion oninicializa se produce siempre en el mismo caso y el onpreinicializa tambien


si usaramos el metodo siguiente:

class a
{
virtual bool inicializa();
};

si esta clase se deriva y no conocemos el funcionamiento de la funcion inicializa deberemos probar si se tiene que llamar al inicio de la funcion derivada o al final y eso es un rollo por que el desarrollos tochos no se pueden perder tiempo en comprobaciones de este tipo

class b : public a
{
virtual bool inicializa()
{
a::inicializa(); // ¿Aqui?
....
a::inicializa(); // ¿o sera aqui?
}
};

saludos






Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.