12. Herencia c++
La herencia
Como bien se sabe la herencia no se reparte: se descuartiza. Bromas aparte, la herencia constituye una de las herramientas mas poderosas de culto OO. Si una clase hereda de la otra, lo que hereda son todos sus atributos y metodos.
Ademas de heredarlos puede sobreescribirlos, tanto los constructores-destructores como los metodos convencionales.
Veremos un ejemplo claro que resume lo que se puede hacer y los efectos de la herencia
Por un lado vemos la clase generica vehiculo y su descendiente: el coche.
La clase Vehiculo
La salida de la ejecucion de Coche.cpp seria:
Como bien se sabe la herencia no se reparte: se descuartiza. Bromas aparte, la herencia constituye una de las herramientas mas poderosas de culto OO. Si una clase hereda de la otra, lo que hereda son todos sus atributos y metodos.
Ademas de heredarlos puede sobreescribirlos, tanto los constructores-destructores como los metodos convencionales.
Veremos un ejemplo claro que resume lo que se puede hacer y los efectos de la herencia
Por un lado vemos la clase generica vehiculo y su descendiente: el coche.
La clase Vehiculo
/** * Vehiculo.hpp * Clase que define el objeto vehiculo * * Pello Xabier Altadill Izura * */ #includeY su implementacion...enum tipo_combustible { QUEROSENO, CANNABIS, GIRASOL, GASOIL, AGUA, PLUTONIO }; class Vehiculo { protected: int cilindrada; tipo_combustible combustible; char *marca; public: Vehiculo(); Vehiculo(char *marca); Vehiculo(int cilindrada, tipo_combustible combustible, char *marca); ~Vehiculo(); Vehiculo(const Vehiculo &); void arrancar(); void mover(int metros); // metodo tipo virtual, util cuando definamos PUNTEROS Y REFERENCIAS a vehiculo virtual void claxon() const { cout << "<clase vehiculo> Mec-meeec!! Que? meeec! Que de que? meec!" << endl; } char *getMarca() const {return this->marca;} tipo_combustible getCombustible() const {return this->combustible;} int getCilindrada() const {return this->cilindrada;} };
/** * Vehiculo.cpp * Fichero que implementa la clase vehiculo * * Pello Xabier Altadill Izura * * Compilacion: g++ -c Vehiculo.cpp */ #include "Vehiculo.hpp" // Constructor Vehiculo::Vehiculo() { cout << "<clase vehiculo> Vehiculo creado" << endl; } // Constructor Vehiculo::Vehiculo(char *marca) { this->marca = marca; cout << "<clase vehiculo> Vehiculo creado con parametro marca: " << marca << endl; } // Constructor con valores iniciados Vehiculo::Vehiculo(int cilindrada, tipo_combustible combustible, char *marca) : cilindrada(cilindrada), combustible(combustible), marca(marca) { cout << "<clase vehiculo> Vehiculo creado con valores: " << endl; cout << "<clase vehiculo> cilindrada: " << cilindrada << endl; cout << "<clase vehiculo> combustible: " << combustible << endl; cout << "<clase vehiculo> marca: " << marca << endl; } // Destructor Vehiculo::~Vehiculo() { cout << "<clase vehiculo> Vehiculo destruido" << endl; } // Constructor copia de vehiculo Vehiculo::Vehiculo(const Vehiculo & vehiculoOrigen) { } // Arrancamos el vehiculo void Vehiculo::arrancar() { cout << "<clase vehiculo> arrancando vehiculo. Brruum!!" << endl; } // Movemos el vehiculo unos metros void Vehiculo::mover(int metros) { cout << "<clase vehiculo> moviendo vehiculo " << metros << " metros" << endl; }El coche, herencia de Vehiculo
/** * Coche.hpp * Clase que define el objeto Coche, hijo de vehiculo, señor del capitalismo * * Pello Xabier Altadill Izura * */ #include "Vehiculo.hpp" class Coche : public Vehiculo { protected: int caballos; char *motor; public: // Atencion: constructor pasando parametros por defecto estilo guru // pero invocando a su clase padre Coche():Vehiculo("Audi") { cout << "<clase coche> Coche destruido invocando al constructor vehiculo" << endl; } // Constructor que sobreescribe al de vehiculo! Coche(char *marca); // Constructor Coche(int cilindrada, tipo_combustible combustible, char *marca); // Constructor Coche(int caballos, char *motor) { this->caballos = caballos; this->motor = motor; cout << "<clase coche> Coche construido con caballos y motor" << endl; } // Destructor ~Coche(); // Constructor copia Coche(const Coche &); // Metodo sobreescrito void arrancar(); // metodo que sobreescribe al virtual void claxon() const; // getter/setter int getCaballos() const {return this->caballos;} // inline char *getMotor() const {return this->motor;} // inline };Y su implementacion
/** * Coche.cpp * Fichero que implementa la clase Coche * * Pello Xabier Altadill Izura * * Compilacion: g++ -c Vehiculo.cpp * g++ Coche.cpp Vehiculo.o -o Coche */ #include "Coche.hpp" // Constructor de coche que sobreescribe Coche::Coche(char *marca) { cout << "<clase coche> Coche construido con marca: " << marca << endl; } // Constructor de coche Coche::Coche(int cilindrada, tipo_combustible combustible, char *marca) { cout << "<clase coche> Coche construido con parametros" << endl; } // Destructor de coche Coche::~Coche() { cout << "<clase coche> Coche destruido" << endl; } // Constructor copia de Coche Coche::Coche(const Coche & cocheOriginal) { marca = new char; marca = cocheOriginal.getMarca(); cout << "<clase coche> Copia de coche" << endl; } // metodo sobreescrito void Coche::arrancar () { cout << "<clase coche> BOOM! pam! pam! pret pret pret... pam! pret pret" << endl; } // metodo que sobreescribe al virtual void Coche::claxon() const { cout << "<clase coche> MOOOOOC!! Mecagon tus muelas MOC-MOOOC!!" << endl; } // Funcion principal int main () { // Creamos varios coches. Veremos que al ser objetos heredados // se invocaran los constructores, copias, y destructores de la clase // padre Vehiculo Coche mibuga = Coche(); Coche tucarro = Coche(mibuga); // probando constructor sobrescrito: se invocan los dos! Coche tequi = Coche("Alfalfa Romero"); // podemos invocar los metodos del padre y usar sus atributos cout << "La marca de mi buga es: " << mibuga.getMarca() << endl; mibuga.arrancar(); // Invocando metodo sobreescrito: solo se invoca el del coche. tucarro.arrancar(); // Y si queremos invocar el metodo del padre?? tequi.Vehiculo::arrancar(); // Creamos otro vehiculo con puntero a un COCHE Vehiculo *vehiculo = new Coche("LanborJini"); // Esto invocara el metodo de vehiculo, el de la clase PADRE vehiculo->arrancar(); vehiculo->mover(3); // Ahora queremos invocar el claxon, pero a cual de los metodos // se invocara, al del Coche o al de la clase vehiculo? al haber // definido el metodo claxon como virtual, se invocara el metodo correcto // que es el del coche (vehiculo es un puntero a coche). vehiculo->claxon(); return 0; }OUTPUT
La salida de la ejecucion de Coche.cpp seria:
<clase vehiculo> Vehiculo creado con parametro marca: Audi <clase coche> Coche destruido invocando al constructor vehiculo <clase vehiculo> Vehiculo creado <clase coche> Copia de coche <clase vehiculo> Vehiculo creado <clase coche> Coche construido con marca: Alfalfa Romero La marca de mi buga es: Audi <clase coche> BOOM! pam! pam! pret pret pret... pam! pret pret <clase coche> BOOM! pam! pam! pret pret pret... pam! pret pret <clase vehiculo> arrancando vehiculo. Brruum!! <clase vehiculo> Vehiculo creado <clase coche> Coche construido con marca: LanborJini <clase vehiculo> arrancando vehiculo. Brruum!! <clase vehiculo> moviendo vehiculo 3 metros <clase coche> MOOOOOC!! Mecagon tus muelas MOC-MOOOC!!