Pensar en C++ (Volumen 1) - Grupo ARCO
Pensar en C++ (Volumen 1) - Grupo ARCO Pensar en C++ (Volumen 1) - Grupo ARCO
✐ ✐ ✐ “Volumen1” — 2012/1/12 — 13:52 — page 320 — #358 ✐ Capítulo 11. Las referencias y el constructor de copia Objetos temporales En la línea 15 se empieza la llamada a f(h), y esta vez ignora el valor de retorno. Puede ver que se invoca el constructor de copia en la línea 16, igual que antes, para pasar el argumento. Y también, igual que antes, en la línea 21 se llama al constructor de copia para el valor de retorno. Pero el constructor de copia necesita una dirección para utilizar como destino (es decir, para trabajar con el puntero this). ¿De dónde procede esta dirección Esto prueba que el compilador puede crear un objeto temporal cuando lo necesita para evaluar adecuadamente una expresión. En este caso, crea uno que ni siquiera se le ve actuar como destino para el valor ignorado retornado por f(). El tiempo de vida de este objeto temporal es tan corto como sea posible para que el programa no se llene de objetos temporales esperando a ser destruidos, lo cual provocaría la utilización ineficaz de recursos valiosos. En algunos casos, el objeto temporal podría pasarse inmediatamente a otra función, pero en este caso no se necesita después de la llamada a la función, así que en cuanto la función termina, llamando al destructor del objeto local (líneas 23 y 24), el objeto temporal también se destruye (líneas 25 y 26). Finalmente, de la línea 28 a la línea 31, se destruye el objeto h2, seguido de h y el contador de objetos vuelve a cero. 11.3.3. El constructor de copia por defecto Como el constructor de copia implementa el paso y retorno por valor, es importante que el compilador cree uno en el caso de estructuras simples (de hecho, es lo mismo que hace C). Sin embargo todo lo que se ha visto es el comportamiento por defecto: una copia bit a bit. Cuando se utilizan tipos más complejos, el compilador de C++ creará un constructor de copia automáticamente si no se implementa explícitamente. De nuevo, una copia bit a bit no tiene sentido, porque no tiene porqué ser el comportamiento que se necesita. He aquí un ejemplo para mostrar el comportamiento más inteligente del compilador. Suponga que crea una nueva clase compuesta por objetos de varias clases diferentes. A esto se le denomina composición, y es una de las formas en las que se pueden hacer nuevas clases a partir de las ya existentes. Ahora desempeñe el papel de un novato que trata de resolver un problema rápidamente creando una nueva clase de esta manera. No sabe nada sobre los constructores de copia, así que no lo implementa. El ejemplo muestra lo que el compilador hace cuando crea un constructor de copia por defecto para su nueva clase: //: C11:DefaultCopyConstructor.cpp // Automatic creation of the copy-constructor #include #include using namespace std; class WithCC { // With copy-constructor public: // Explicit default constructor required: WithCC() {} WithCC(const WithCC&) { cout
✐ ✐ ✐ “Volumen1” — 2012/1/12 — 13:52 — page 321 — #359 ✐ 11.3. El constructor de copia }; class WoCC { // Without copy-constructor string id; public: WoCC(const string& ident = "") : id(ident) {} void print(const string& msg = "") const { if(msg.size() != 0) cout
- Page 307 and 308: ✐ ✐ ✐ “Volumen1” — 2012
- Page 309 and 310: ✐ ✐ ✐ “Volumen1” — 2012
- Page 311 and 312: ✐ ✐ ✐ “Volumen1” — 2012
- Page 313 and 314: ✐ ✐ ✐ “Volumen1” — 2012
- Page 315 and 316: ✐ ✐ ✐ “Volumen1” — 2012
- Page 317 and 318: ✐ ✐ ✐ “Volumen1” — 2012
- Page 319 and 320: ✐ ✐ ✐ “Volumen1” — 2012
- Page 321 and 322: ✐ ✐ ✐ “Volumen1” — 2012
- Page 323 and 324: ✐ ✐ ✐ “Volumen1” — 2012
- Page 325 and 326: ✐ ✐ ✐ “Volumen1” — 2012
- Page 327 and 328: ✐ ✐ ✐ “Volumen1” — 2012
- Page 329 and 330: ✐ ✐ ✐ “Volumen1” — 2012
- Page 331 and 332: ✐ ✐ ✐ “Volumen1” — 2012
- Page 333 and 334: ✐ ✐ ✐ “Volumen1” — 2012
- Page 335 and 336: ✐ ✐ ✐ “Volumen1” — 2012
- Page 337 and 338: ✐ ✐ ✐ “Volumen1” — 2012
- Page 339 and 340: ✐ ✐ ✐ “Volumen1” — 2012
- Page 341 and 342: ✐ ✐ ✐ “Volumen1” — 2012
- Page 343 and 344: ✐ ✐ ✐ “Volumen1” — 2012
- Page 345 and 346: ✐ ✐ ✐ “Volumen1” — 2012
- Page 347 and 348: ✐ ✐ ✐ “Volumen1” — 2012
- Page 349 and 350: ✐ ✐ ✐ “Volumen1” — 2012
- Page 351 and 352: ✐ ✐ ✐ “Volumen1” — 2012
- Page 353 and 354: ✐ ✐ ✐ “Volumen1” — 2012
- Page 355 and 356: ✐ ✐ ✐ “Volumen1” — 2012
- Page 357: ✐ ✐ ✐ “Volumen1” — 2012
- Page 361 and 362: ✐ ✐ ✐ “Volumen1” — 2012
- Page 363 and 364: ✐ ✐ ✐ “Volumen1” — 2012
- Page 365 and 366: ✐ ✐ ✐ “Volumen1” — 2012
- Page 367 and 368: ✐ ✐ ✐ “Volumen1” — 2012
- Page 369 and 370: ✐ ✐ ✐ “Volumen1” — 2012
- Page 371 and 372: ✐ ✐ ✐ “Volumen1” — 2012
- Page 373 and 374: ✐ ✐ ✐ “Volumen1” — 2012
- Page 375 and 376: ✐ ✐ ✐ “Volumen1” — 2012
- Page 377 and 378: ✐ ✐ ✐ “Volumen1” — 2012
- Page 379 and 380: ✐ ✐ ✐ “Volumen1” — 2012
- Page 381 and 382: ✐ ✐ ✐ “Volumen1” — 2012
- Page 383 and 384: ✐ ✐ ✐ “Volumen1” — 2012
- Page 385 and 386: ✐ ✐ ✐ “Volumen1” — 2012
- Page 387 and 388: ✐ ✐ ✐ “Volumen1” — 2012
- Page 389 and 390: ✐ ✐ ✐ “Volumen1” — 2012
- Page 391 and 392: ✐ ✐ ✐ “Volumen1” — 2012
- Page 393 and 394: ✐ ✐ ✐ “Volumen1” — 2012
- Page 395 and 396: ✐ ✐ ✐ “Volumen1” — 2012
- Page 397 and 398: ✐ ✐ ✐ “Volumen1” — 2012
- Page 399 and 400: ✐ ✐ ✐ “Volumen1” — 2012
- Page 401 and 402: ✐ ✐ ✐ “Volumen1” — 2012
- Page 403 and 404: ✐ ✐ ✐ “Volumen1” — 2012
- Page 405 and 406: ✐ ✐ ✐ “Volumen1” — 2012
- Page 407 and 408: ✐ ✐ ✐ “Volumen1” — 2012
✐<br />
✐<br />
✐<br />
“Volum<strong>en</strong>1” — 2012/1/12 — 13:52 — page 320 — #358<br />
✐<br />
Capítulo 11. Las refer<strong>en</strong>cias y el constructor de copia<br />
Objetos temporales<br />
En la línea 15 se empieza la llamada a f(h), y esta vez ignora el valor de retorno.<br />
Puede ver que se invoca el constructor de copia <strong>en</strong> la línea 16, igual que antes, para<br />
pasar el argum<strong>en</strong>to. Y también, igual que antes, <strong>en</strong> la línea 21 se llama al constructor<br />
de copia para el valor de retorno. Pero el constructor de copia necesita una dirección<br />
para utilizar como destino (es decir, para trabajar con el puntero this). ¿De dónde<br />
procede esta dirección<br />
Esto prueba que el compilador puede crear un objeto temporal cuando lo necesita<br />
para evaluar adecuadam<strong>en</strong>te una expresión. En este caso, crea uno que ni siquiera<br />
se le ve actuar como destino para el valor ignorado retornado por f(). El tiempo<br />
de vida de este objeto temporal es tan corto como sea posible para que el programa<br />
no se ll<strong>en</strong>e de objetos temporales esperando a ser destruidos, lo cual provocaría la<br />
utilización ineficaz de recursos valiosos. En algunos casos, el objeto temporal podría<br />
pasarse inmediatam<strong>en</strong>te a otra función, pero <strong>en</strong> este caso no se necesita después de<br />
la llamada a la función, así que <strong>en</strong> cuanto la función termina, llamando al destructor<br />
del objeto local (líneas 23 y 24), el objeto temporal también se destruye (líneas 25 y<br />
26).<br />
Finalm<strong>en</strong>te, de la línea 28 a la línea 31, se destruye el objeto h2, seguido de h y el<br />
contador de objetos vuelve a cero.<br />
11.3.3. El constructor de copia por defecto<br />
Como el constructor de copia implem<strong>en</strong>ta el paso y retorno por valor, es importante<br />
que el compilador cree uno <strong>en</strong> el caso de estructuras simples (de hecho, es lo<br />
mismo que hace C). Sin embargo todo lo que se ha visto es el comportami<strong>en</strong>to por<br />
defecto: una copia bit a bit.<br />
Cuando se utilizan tipos más complejos, el compilador de <strong>C++</strong> creará un constructor<br />
de copia automáticam<strong>en</strong>te si no se implem<strong>en</strong>ta explícitam<strong>en</strong>te. De nuevo,<br />
una copia bit a bit no ti<strong>en</strong>e s<strong>en</strong>tido, porque no ti<strong>en</strong>e porqué ser el comportami<strong>en</strong>to<br />
que se necesita.<br />
He aquí un ejemplo para mostrar el comportami<strong>en</strong>to más intelig<strong>en</strong>te del compilador.<br />
Suponga que crea una nueva clase compuesta por objetos de varias clases<br />
difer<strong>en</strong>tes. A esto se le d<strong>en</strong>omina composición, y es una de las formas <strong>en</strong> las que se<br />
pued<strong>en</strong> hacer nuevas clases a partir de las ya exist<strong>en</strong>tes. Ahora desempeñe el papel<br />
de un novato que trata de resolver un problema rápidam<strong>en</strong>te creando una nueva<br />
clase de esta manera. No sabe nada sobre los constructores de copia, así que no lo implem<strong>en</strong>ta.<br />
El ejemplo muestra lo que el compilador hace cuando crea un constructor<br />
de copia por defecto para su nueva clase:<br />
//: C11:DefaultCopyConstructor.cpp<br />
// Automatic creation of the copy-constructor<br />
#include <br />
#include <br />
using namespace std;<br />
class WithCC { // With copy-constructor<br />
public:<br />
// Explicit default constructor required:<br />
WithCC() {}<br />
WithCC(const WithCC&) {<br />
cout