Pensar en C++ (Volumen 1) - Grupo ARCO
Pensar en C++ (Volumen 1) - Grupo ARCO
Pensar en C++ (Volumen 1) - Grupo ARCO
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 />
✐