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

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

✐<br />

✐<br />

✐<br />

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

✐<br />

Capítulo 14. Her<strong>en</strong>cia y Composición<br />

orpr<strong>en</strong>dido ¡este mecanismo de comprobación de tipos seguro es gratuito, <strong>en</strong><br />

push(), peek() y pop! Al compilador se le proporciona información extra acerca de<br />

los tipos y éste lo utiliza <strong>en</strong> tiempo de compilación, pero las funciones son inline y<br />

no es necesario ningún código extra.<br />

La ocultación de nombres <strong>en</strong>tra <strong>en</strong> acción <strong>en</strong> la función push() que ti<strong>en</strong>e la signatura<br />

difer<strong>en</strong>te: la lista de argum<strong>en</strong>tos. Si se tuvies<strong>en</strong> dos versiones de push() <strong>en</strong> la<br />

misma clase, t<strong>en</strong>drían que ser sobrecargadas, pero <strong>en</strong> este caso la sobrecarga no es<br />

lo que deseamos porque todavía permitiría pasar cualquier tipo de puntero a push<br />

como void *. Afortunadam<strong>en</strong>te, <strong>C++</strong> esconde la versión push (void *) <strong>en</strong> la clase base<br />

<strong>en</strong> favor de la nueva versión que es definida <strong>en</strong> la clase derivada, de este modo, solo<br />

se permite utilizar la función push() con punteros a String <strong>en</strong> StringStack.<br />

Ahora podemos asegurar que se conoce exactam<strong>en</strong>te el tipo de objeto que esta<br />

<strong>en</strong> el cont<strong>en</strong>edor, el destructor funcionará correctam<strong>en</strong>te y problema esta resuelto -<br />

o al m<strong>en</strong>os, un parte del procedimi<strong>en</strong>to. Si utiliza push( ) con un puntero a String <strong>en</strong><br />

StringStack, <strong>en</strong>tonces (según el significado de StringStack) también se esta pasando<br />

el puntero a StringStack. Si utiliza pop(), no solo consigue puntero, sino que a la vez<br />

el propietario. Cualquier puntero que se haya dejado <strong>en</strong> StringStack será borrado<br />

cuando el destructor sea invocado. Puesto que siempre son punteros a Strings y la<br />

declaración delete esta funcionando con punteros a String <strong>en</strong> vez de punteros a void,<br />

la destrucción se realiza de forma adecuada y todo funciona correctam<strong>en</strong>te.<br />

Esto es una desv<strong>en</strong>taja: esta clase solo funciona con punteros de cad<strong>en</strong>as. Si se<br />

desea un Stack que funcione con cualquier variedad de objetos, se debe escribir una<br />

nueva versión de la clase que funcione con ese nuevo tipo de objeto. Esto puede<br />

convertirse rápidam<strong>en</strong>te <strong>en</strong> una tarea tediosa, pero finalm<strong>en</strong>te es resulta utilizando<br />

plantillas como se vera <strong>en</strong> el capítulo 16.<br />

Exist<strong>en</strong> consideraciones adicionales sobre este ejemplo: el cambio de la interfaz<br />

<strong>en</strong> Stack <strong>en</strong> el proceso de her<strong>en</strong>cia. Si la interfaz es difer<strong>en</strong>te, <strong>en</strong>tonces StringStack<br />

no es realm<strong>en</strong>te un Stack, y nunca será posible usar de forma correcta un StringStack<br />

como Stack. Esto hace que el uso de la her<strong>en</strong>cia sea cuestionable <strong>en</strong> este punto; si<br />

no se esta creando un StringStack del tipo Stack, <strong>en</strong>tonces, porque hereda de él. Más<br />

adelante, s<strong>en</strong> este mismo capítulo se mostrará una versión más adecuada.<br />

14.5. Funciones que no heredan automáticam<strong>en</strong>te<br />

No todas las funciones son heredadas automáticam<strong>en</strong>te desde la clase base a la<br />

clase derivada. Los constructores y destructores manejan la creación y la destrucción<br />

de un objeto y sólo ellos sab<strong>en</strong> que hacer con los aspectos de un objeto <strong>en</strong> sus<br />

clases particulares y por ello los constructores y destructores inferiores de la jerarquía<br />

deb<strong>en</strong> llamarlos. Así, los constructores y destructores no se heredan y deb<strong>en</strong> ser<br />

creados específicam<strong>en</strong>te <strong>en</strong> cada clase derivada.<br />

Además, operator= tampoco se hereda porque realiza una acción parecida al<br />

constructor. Esto es, sólo porque conoce como asignar todos los miembros de un<br />

objeto, la parte izquierda del = a la parte derecha del otro objeto, no significa que la<br />

asignación t<strong>en</strong>drá el mismo significado después de la her<strong>en</strong>cia.<br />

En la her<strong>en</strong>cia, estas funciones son creadas por el compilador si no son creadas<br />

por usted. (Con constructores, no se pued<strong>en</strong> crear constructores para que el compilador<br />

cree el constructor por defecto y el constructor copia.) Esto fue brevem<strong>en</strong>te<br />

descrito <strong>en</strong> el capítulo 6. Los constructores creados se usan <strong>en</strong> inicialización de sus<br />

miembros y la creación del operator= usa la asignación de los miembros. A continuación,<br />

un ejemplo de las funciones que son creadas por el compilador.<br />

414<br />

✐<br />

✐<br />

✐<br />

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

Saved successfully!

Ooh no, something went wrong!