13.01.2015 Views

Pensar en C++ (Volumen 1) - Grupo ARCO

Pensar en C++ (Volumen 1) - Grupo ARCO

Pensar en C++ (Volumen 1) - Grupo ARCO

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

✐<br />

✐<br />

✐<br />

“Volum<strong>en</strong>1” — 2012/1/12 — 13:52 — page 461 — #499<br />

✐<br />

15.10. funciones virtuales y constructores<br />

Todos los constructores de la clase base son siempre llamados <strong>en</strong> el constructor de<br />

una clase heredada. Esto ti<strong>en</strong>e s<strong>en</strong>tido porque el constructor ti<strong>en</strong>e un trabajo especial:<br />

ver que el objeto está construido de forma apropiada. Una clase derivada sólo ti<strong>en</strong>e<br />

acceso a sus propios miembros, y no a los de la clase base. únicam<strong>en</strong>te el constructor<br />

de la clase base puede inicializar de forma adecuada a sus propios elem<strong>en</strong>tos. Por<br />

lo tanto es es<strong>en</strong>cial que se llame a todos los constructores; de otra forma el objeto<br />

no estará construido de forma adecuada. Esto es por lo que el compilador obliga a<br />

hacer una llamada por cada trozo <strong>en</strong> una clase derivada. Se llamará al constructor<br />

por defecto si no se hace una llamada explícita a un constructor de la clase base. Si<br />

no existe constructor por defecto, el compilador lo creará.<br />

El ord<strong>en</strong> de las llamadas al constructor es importante. Cuando se hereda, se sabe<br />

todo sobre la clase base y se puede acceder a todos los miembros públicos y protegidos<br />

(public y protected) de la clase base. ésto significa que se puede asumir que<br />

todos los miembros de la clase base son válidos cuando se está <strong>en</strong> la clase derivada.<br />

En una función miembro normal, la construcción ya ha ocurrido, por lo que todos<br />

los miembros de todas las partes del objeto ya han sido construidos. D<strong>en</strong>tro del constructor,<br />

sin embargo, hay que asumir que todos los miembros que se us<strong>en</strong> han sido<br />

construidos. La única manera de garantizarlo es llamando primero al constructor de<br />

la clase base. Entonces cuando se esté <strong>en</strong> el constructor de la clase derivada, todos los<br />

miembros a los que se pueda acceder <strong>en</strong> la clase base han sido inicializados. "Saber<br />

que todos los miembros son válidos" d<strong>en</strong>tro del constructor es también la razón por<br />

la que, d<strong>en</strong>tro de lo posible, se debe inicializar todos los objetos miembros (es decir,<br />

los objetos puestos <strong>en</strong> la clase mediante composición). Si se sigue ésta práctica, se<br />

puede asumir que todos los miembros de la clase base y los miembros objetos del<br />

objeto actual han sido inicializados.<br />

15.10.2. Comportami<strong>en</strong>to de las funciones virtuales d<strong>en</strong>tro<br />

de los constructores<br />

La jerarquía de las llamadas a los constructores plantea un interesante dilema.<br />

¿Qué ocurre si se está d<strong>en</strong>tro de un constructor y se llama a una función virtual<br />

D<strong>en</strong>tro de una función miembro ordinaria se puede imaginar que ocurrirá - la llamada<br />

virtual es resuelta <strong>en</strong> tiempo de ejecución porque el objeto no puede conocer<br />

si la función miembro es de la clase <strong>en</strong> la que está o es de una clase derivada. Por<br />

consist<strong>en</strong>cia, se podría p<strong>en</strong>sar que también es lo que debería ocurrir d<strong>en</strong>tro de los<br />

constructores.<br />

No es el caso. Si se llama a una función virtual d<strong>en</strong>tro de un constructor, sólo se<br />

usa la versión local de la función. Es decir, el mecanismo virtual no funciona d<strong>en</strong>tro<br />

del constructor.<br />

éste comportami<strong>en</strong>to ti<strong>en</strong>e s<strong>en</strong>tido por dos motivos. Conceptualm<strong>en</strong>te, el trabajo<br />

del constructor es dar al objeto una exist<strong>en</strong>cia. D<strong>en</strong>tro de cualquier constructor, el<br />

objeto puede ser formado sólo parcialm<strong>en</strong>te - se puede saber sólo que los objetos<br />

de la clase base han sido inicializados, pero no se puede saber que clases heredan<br />

de ésta. Una función virtual, sin embargo, se mueve "arriba" y "abajo" d<strong>en</strong>tro de la<br />

jerarquía de her<strong>en</strong>cia. Llama a una función de una clase derivada. Si se pudiera hacer<br />

esto d<strong>en</strong>tro de un constructor, se estaría llamando a una función que debe manejar<br />

miembros que todavía no han sido inicializados, una receta segura para el desastre.<br />

El segundo motivo es mecánico. Cuando se llama a un constructor, una de las<br />

primeras cosas que hace es inicializar su VPTR. Sin embargo, sólo puede saber que<br />

es del tipo "actual" - el tipo para el que se ha escrito el constructor. El código del<br />

constructor ignora completam<strong>en</strong>te si el objeto está <strong>en</strong> la base de otra clase. Cuando<br />

461<br />

✐<br />

✐<br />

✐<br />

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!