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 458 — #496 ✐ Capítulo 15. Polimorfismo y Funciones virtuales Derived1 d1; int x = d1.f(); d1.f(s); Derived2 d2; x = d2.f(); //! d2.f(s); // string version hidden Derived4 d4; x = d4.f(1); //! x = d4.f(); // f() version hidden //! d4.f(s); // string version hidden Base& br = d4; // Upcast //! br.f(1); // Derived version unavailable br.f(); // Base version available br.f(s); // Base version abailable } ///:~ La primera cosa a resaltar es que en Derived3, el compilador no permitirá cambiar el tipo de retorno de una función sobreescrita (lo permitiría si f() no fuera virtual). ésta es una restricción importante porque el compilador debe garantizar que se pueda llamar de forma "polimórfica" a la función a través de la clase base, y si la clase base está esperando que f() devuelva un int, entonces la versión de f() de la clase derivada debe mantener ese compromiso o si no algo fallará. La regla que se enseño en el capítulo 14 todavía funciona: si se sobreescribe una de las funciones miembro sobrecargadas de la clase base, las otras versiones sobrecargadas estarán ocultas en la clase derivada. En el main() el código de Derived4 muestra lo que ocurre incluso si la nueva versión de f() no está actualmente sobreescribiendo una función virtual existente de la interfaz - ambas versiones de f() en la clase base estan ocultas por f(int). Sin embargo, si se hace un upcast de d4 a B- ase, entonces únicamente las versiones de la clase base estarán disponibles (porque es el compromiso de la clase base) y la versión de la clase derivada no está disponible (debido a que no está especificada en la clase base). 15.9.1. Tipo de retorno variante La clase Derived3 de arriba viene a sugerir que no se puede modificar el tipo de retorno de una función virtual cuando es sobreescrita. En general es verdad, pero hay un caso especial en el que se puede modificar ligeramente el tipo de retorno. Si se está devolviendo un puntero o una referencia a una clase base, entonces la versión sobreescrita de la función puede devolver un puntero o una referencia a una clase derivada. Por ejemplo: //: C15:VariantReturn.cpp // Returning a pointer or reference to a derived // type during ovverriding #include #include using namespace std; class PetFood { public: virtual string foodType() const = 0; }; 458 ✐ ✐ ✐ ✐
✐ ✐ ✐ “Volumen1” — 2012/1/12 — 13:52 — page 459 — #497 ✐ 15.9. Sobrecargar y redefinir class Pet { public: virtual string type() const = 0; virtual PetFood* eats() = 0; }; class Bird : public Pet { public: string type() const { return "Bird"; } class BirdFood : public PetFood { public: string foodType() const { return "Bird food"; } }; // Upcast to base type: PetFood* eats() { return &bf; } private: BirdFood bf; }; class Cat : public Pet { public: string type() const { return "Cat"; } class CatFood : public PetFood { public: string foodType() const { return "Birds"; } }; // Return exact type instead: CatFood* eats() { return &cf; } private: CatFood cf; }; int main() { Bird b; Cat c; Pet* p[] = { &b, &c, }; for(int i = 0; i < sizeof p / sizeof *p; i++) cout type() foodType() upcast de BirdFood a PetFood en el retorno de la función. Pero en Cat, el tipo devuelto por eats() es un puntero a CatFood, que es un tipo derivado de PetFood. El hecho de que el tipo de retorno esté heredado del tipo 459 ✐ ✐ ✐ ✐
- Page 445 and 446: ✐ ✐ ✐ “Volumen1” — 2012
- Page 447 and 448: ✐ ✐ ✐ “Volumen1” — 2012
- Page 449 and 450: ✐ ✐ ✐ “Volumen1” — 2012
- Page 451 and 452: ✐ ✐ ✐ “Volumen1” — 2012
- Page 453 and 454: ✐ ✐ ✐ “Volumen1” — 2012
- Page 455 and 456: ✐ ✐ ✐ “Volumen1” — 2012
- Page 457 and 458: ✐ ✐ ✐ “Volumen1” — 2012
- Page 459 and 460: ✐ ✐ ✐ “Volumen1” — 2012
- Page 461 and 462: ✐ ✐ ✐ “Volumen1” — 2012
- Page 463 and 464: ✐ ✐ ✐ “Volumen1” — 2012
- Page 465 and 466: ✐ ✐ ✐ “Volumen1” — 2012
- Page 467 and 468: ✐ ✐ ✐ “Volumen1” — 2012
- Page 469 and 470: ✐ ✐ ✐ “Volumen1” — 2012
- Page 471 and 472: ✐ ✐ ✐ “Volumen1” — 2012
- Page 473 and 474: ✐ ✐ ✐ “Volumen1” — 2012
- Page 475 and 476: ✐ ✐ ✐ “Volumen1” — 2012
- Page 477 and 478: ✐ ✐ ✐ “Volumen1” — 2012
- Page 479 and 480: ✐ ✐ ✐ “Volumen1” — 2012
- Page 481 and 482: ✐ ✐ ✐ “Volumen1” — 2012
- Page 483 and 484: ✐ ✐ ✐ “Volumen1” — 2012
- Page 485 and 486: ✐ ✐ ✐ “Volumen1” — 2012
- Page 487 and 488: ✐ ✐ ✐ “Volumen1” — 2012
- Page 489 and 490: ✐ ✐ ✐ “Volumen1” — 2012
- Page 491 and 492: ✐ ✐ ✐ “Volumen1” — 2012
- Page 493 and 494: ✐ ✐ ✐ “Volumen1” — 2012
- Page 495: ✐ ✐ ✐ “Volumen1” — 2012
- Page 499 and 500: ✐ ✐ ✐ “Volumen1” — 2012
- Page 501 and 502: ✐ ✐ ✐ “Volumen1” — 2012
- Page 503 and 504: ✐ ✐ ✐ “Volumen1” — 2012
- Page 505 and 506: ✐ ✐ ✐ “Volumen1” — 2012
- Page 507 and 508: ✐ ✐ ✐ “Volumen1” — 2012
- Page 509 and 510: ✐ ✐ ✐ “Volumen1” — 2012
- Page 511 and 512: ✐ ✐ ✐ “Volumen1” — 2012
- Page 513 and 514: ✐ ✐ ✐ “Volumen1” — 2012
- Page 515 and 516: ✐ ✐ ✐ “Volumen1” — 2012
- Page 517 and 518: ✐ ✐ ✐ “Volumen1” — 2012
- Page 519 and 520: ✐ ✐ ✐ “Volumen1” — 2012
- Page 521 and 522: ✐ ✐ ✐ “Volumen1” — 2012
- Page 523 and 524: ✐ ✐ ✐ “Volumen1” — 2012
- Page 525 and 526: ✐ ✐ ✐ “Volumen1” — 2012
- Page 527 and 528: ✐ ✐ ✐ “Volumen1” — 2012
- Page 529 and 530: ✐ ✐ ✐ “Volumen1” — 2012
- Page 531 and 532: ✐ ✐ ✐ “Volumen1” — 2012
- Page 533 and 534: ✐ ✐ ✐ “Volumen1” — 2012
- Page 535 and 536: ✐ ✐ ✐ “Volumen1” — 2012
- Page 537 and 538: ✐ ✐ ✐ “Volumen1” — 2012
- Page 539 and 540: ✐ ✐ ✐ “Volumen1” — 2012
- Page 541 and 542: ✐ ✐ ✐ “Volumen1” — 2012
- Page 543 and 544: ✐ ✐ ✐ “Volumen1” — 2012
- Page 545 and 546: ✐ ✐ ✐ “Volumen1” — 2012
✐<br />
✐<br />
✐<br />
“Volum<strong>en</strong>1” — 2012/1/12 — 13:52 — page 458 — #496<br />
✐<br />
Capítulo 15. Polimorfismo y Funciones virtuales<br />
Derived1 d1;<br />
int x = d1.f();<br />
d1.f(s);<br />
Derived2 d2;<br />
x = d2.f();<br />
//! d2.f(s); // string version hidd<strong>en</strong><br />
Derived4 d4;<br />
x = d4.f(1);<br />
//! x = d4.f(); // f() version hidd<strong>en</strong><br />
//! d4.f(s); // string version hidd<strong>en</strong><br />
Base& br = d4; // Upcast<br />
//! br.f(1); // Derived version unavailable<br />
br.f(); // Base version available<br />
br.f(s); // Base version abailable<br />
} ///:~<br />
La primera cosa a resaltar es que <strong>en</strong> Derived3, el compilador no permitirá cambiar<br />
el tipo de retorno de una función sobreescrita (lo permitiría si f() no fuera virtual).<br />
ésta es una restricción importante porque el compilador debe garantizar que<br />
se pueda llamar de forma "polimórfica" a la función a través de la clase base, y si la<br />
clase base está esperando que f() devuelva un int, <strong>en</strong>tonces la versión de f() de la<br />
clase derivada debe mant<strong>en</strong>er ese compromiso o si no algo fallará.<br />
La regla que se <strong>en</strong>seño <strong>en</strong> el capítulo 14 todavía funciona: si se sobreescribe una<br />
de las funciones miembro sobrecargadas de la clase base, las otras versiones sobrecargadas<br />
estarán ocultas <strong>en</strong> la clase derivada. En el main() el código de Derived4<br />
muestra lo que ocurre incluso si la nueva versión de f() no está actualm<strong>en</strong>te sobreescribi<strong>en</strong>do<br />
una función virtual exist<strong>en</strong>te de la interfaz - ambas versiones de f() <strong>en</strong><br />
la clase base estan ocultas por f(int). Sin embargo, si se hace un upcast de d4 a B-<br />
ase, <strong>en</strong>tonces únicam<strong>en</strong>te las versiones de la clase base estarán disponibles (porque<br />
es el compromiso de la clase base) y la versión de la clase derivada no está disponible<br />
(debido a que no está especificada <strong>en</strong> la clase base).<br />
15.9.1. Tipo de retorno variante<br />
La clase Derived3 de arriba vi<strong>en</strong>e a sugerir que no se puede modificar el tipo<br />
de retorno de una función virtual cuando es sobreescrita. En g<strong>en</strong>eral es verdad, pero<br />
hay un caso especial <strong>en</strong> el que se puede modificar ligeram<strong>en</strong>te el tipo de retorno. Si<br />
se está devolvi<strong>en</strong>do un puntero o una refer<strong>en</strong>cia a una clase base, <strong>en</strong>tonces la versión<br />
sobreescrita de la función puede devolver un puntero o una refer<strong>en</strong>cia a una clase<br />
derivada. Por ejemplo:<br />
//: C15:VariantReturn.cpp<br />
// Returning a pointer or refer<strong>en</strong>ce to a derived<br />
// type during ovverriding<br />
#include <br />
#include <br />
using namespace std;<br />
class PetFood {<br />
public:<br />
virtual string foodType() const = 0;<br />
};<br />
458<br />
✐<br />
✐<br />
✐<br />
✐