Una de las maneras más claras de determinar si debe utilizar la composición o la herencia es preguntarse si alguna vez necesitará hacer upcasting desde su nueva clase. Anteriormente, en este capítulo, la clase Stack se especializó utilizando la herencia. Sin embargo, lo más probable es que los objetos StringStack se utilicen sólo como contenedores de string y nunca se haga upcasting con ellos, así que una alternativa más apropiada es la composición:
//: C14:InheritStack2.cpp // Composition vs. inheritance #include "../C09/Stack4.h" #include "../require.h" #include <iostream> #include <fstream> #include <string> using namespace std; class StringStack { Stack stack; // Embed instead of inherit public: void push(string* str) { stack.push(str); } string* peek() const { return (string*)stack.peek(); } string* pop() { return (string*)stack.pop(); } }; int main() { ifstream in("InheritStack2.cpp"); assure(in, "InheritStack2.cpp"); string line; StringStack textlines; while(getline(in, line)) textlines.push(new string(line)); string* s; while((s = textlines.pop()) != 0) // No cast! cout << *s << endl; } ///:~
Listado 14.19. C14/InheritStack2.cpp
El fichero es idéntico a InheritStack.cpp, excepto que hay un objeto Stack alojado en StringStack y se llama a las funciones miembro del objeto alojado. Sigue sin haber sobrecarga de tiempo ni de espacio, porque el subobjeto ocupa el mismo espacio y toda la comprobación de tipos adicional se realiza en tiempo de compilación.
Aunque tiende a resultar más confuso, también podría utilizar la herencia privada para expresar «implementado en términos de». Esto también resolvería el problema de forma adecuada. Sin embargo, un caso en el que esto cobra importancia es cuando podría estar justificada la herencia múltiple. En ese caso, si encuentra un diseño en el que se pueda utilizar la composición en vez de la herencia, puede que consiga eliminar la necesidad de la herencia múltiple.