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

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

arco.esi.uclm.es
from arco.esi.uclm.es More from this publisher
13.01.2015 Views

✐ ✐ ✐ “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 ✐ ✐ ✐ ✐

✐<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 />

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

Saved successfully!

Ooh no, something went wrong!