10.
3 Compare y contraste la asignación dinámica de memoria
con los operadores de desasignación new, new [ ], delete y
delete [ ].
10.5 ¿Puede una definición correcta de la clase Tiempo incluir
los dos constructores que se muestran a continuación? Si no
es así, explique por qué.
Tiempo( int h = 0, int m = 0, int s = 0 );
Tiempo();
10.7 Modifique que la clase Fecha en la figura 10.10 para que
tenga las siguientes herramientas: a) Imprimir la fecha en
varios formatos, como
DDD AAAA
MM/DD/AA
Junio 14, 1992
b) Usar constructores sobrecargados para crear objetos Fecha
inicializados con fechas de los formatos en la parte (a).
c) Crear un constructor de Fecha que lea la fecha del sistema
utilizando las funciones de la biblioteca estándar del
encabezado , y que establezca los miembros de Fecha.
(Consulte la documentación de referencia de su compilador, o
el sitio www.cplusplus.com/ref/ctime/index.html para obtener
información sobre las funciones en el encabezado <ctime> ).
En el capítulo 11, podremos crear operadores para evaluar la
igualdad de dos fechas y para comparar fechas y determinar si
una fecha es anterior, o posterior, a otra.
10.9 Cree la clase ConjuntoEnteros para la que cada objeto
pueda contener enteros en el rango de 0 a 100. Un conjunto se
representa en forma interna como un arreglo de unos y ceros.
El elemento a[ i ] del arreglo es 1 si el entero i se encuentra en
el conjunto. El elemento a[ j ] del arreglo es 0 si el entero j no
se encuentra en el conjunto. El constructor predeterminado
inicializa un conjunto que se denomina “conjunto vacío”; es
decir, un conjunto cuya representación de arreglo contiene
sólo ceros.
Proporcione funciones miembro para las operaciones
comunes de los conjuntos. Por ejemplo, proporcione una
función miembro llamada unionDeConjuntos que cree un tercer
conjunto que sea la unión teórica de dos conjuntos existentes
(es decir, un elemento del arreglo del tercer conjunto se
establece en 1 si ese elemento es 1 en cualquiera, o en ambos
de los conjuntos existentes, y un elemento del arreglo del
tercer conjunto se establece en 0 si ese elemento es 0 en cada
uno de los conjuntos existentes).
Proporcione una función miembro llamada
interseccionDeConjuntos, para crear un tercer conjunto que
sea la intersección teórica de dos conjuntos existentes (es
decir, un elemento del arreglo del tercer conjunto se establece
en 0 si ese elemento es 0 en uno o ambos de los conjuntos
existentes, y un elemento del arreglo del tercer conjunto se
establece en 1 si ese elemento es 1 en cada uno de los
conjuntos existentes). Proporcione una función miembro
llamada insertarElemento, que inserte un nuevo entero k en un
conjunto (estableciendo a[ k ] en 1). Proporcione una función
miembro llamada eliminarElemento que elimine el entero m
(estableciendo a[ m ] en 0).
Proporcione una función miembro llamada imprimirConjunto
que imprima un conjunto como una lista de números
separados por espacios. Imprima sólo los elementos que estén
presentes en el conjunto (es decir, que su posición en el
arreglo tenga un valor de 1). Imprima --- para un conjunto vacío.
Proporcione una función miembro llamada esIgualA que
determine si dos conjuntos son iguales. Proporcione un
constructor adicional que reciba un arreglo de enteros y el
tamaño de ese arreglo, y que utilice el arreglo para inicializar
un objeto conjunto.
Ahora escriba un programa controlador para probar su clase
ConjuntoEnteros. Cree instancias de varios objetos
ConjuntoEnteros. Pruebe que todas sus funciones miembro
trabajen en forma apropiada.
11.7 Los operadores que no se pueden sobrecargar
son __________, __________, __________ y __________.
11.9 (Ejercicio final de sobrecarga de operadores) Para apreciar el cuidado que
se debe poner al seleccionar operadores para sobrecargar,
liste cada uno de los operadores que se pueden sobrecargar y,
para cada uno de ellos, liste un posible significado (o varios,
según sea apropiado) para cada una de varias de las clases
que ha estudiado en este texto. Le sugerimos que pruebe con:
a) Array
b) Pila
c) String
Después de hacer esto, comente cuáles operadores parecen
tener significado para una amplia variedad de clases. ¿Cuáles
operadores parecen tener poco valor para la sobrecarga?
¿Cuáles operadores parecen ambiguos?
11 11. Un buen ejemplo de cómo sobrecargar el operador () de
llamadas a funciones es permitir otra forma de subíndices
dobles de arreglos comunes en ciertos lenguajes de
programación. En vez de decir
tableroAjedrez[ fila ][ columna ]
para un arreglo de objetos, sobrecargue el operador de
llamadas a funciones para permitir la siguiente forma alterna:
tableroAjedrez( fila, columna )
Cree una clase llamada ArregloSubindiceDoble que tenga
características similares a la clase Array de las figuras 11.6 y
11.7. Al momento de la construcción, la clase debe poder crear
un arreglo de cualquier número de filas y columnas. La clase
debe proporcionar el operator() para realizar operaciones con
doble subíndice. Por ejemplo, en un objeto
ArregloSubindiceDoble de 3 por 5 llamado a, el usuario podría
escribir a( 1, 3 ) para acceder al elemento en la fi la 1 y la
columna 3. Recuerde que operator() puede recibir cualquier
número de argumentos (en la clase String en las figuras 11.9 y
11.10 podrá ver un ejemplo de operator()). La representación
subyacente del arreglo con doble subíndice debe ser un
arreglo de enteros con un subíndice, con un número de
elementos equivalente a filas * columnas. La función operator()
debe realizar la aritmética de apuntadores apropiada para
acceder a cada elemento del arreglo. Debe haber dos versiones
de operator(): una que devuelva int & (de manera que un
elemento de un objeto ArregloSubindiceDoble pueda usarse
como lvalue) y otra que devuelva const int & (de manera que un
elemento de un objeto constArregloSubindiceDoble pueda
usarse sólo como rvalue). La clase debe también proporcionar
los siguientes operadores: ==, !=, =, << ( para imprimir el
arreglo en formato de fila y columna) y >> ( para recibir todo el
contenido completo del arreglo)
11.15 Cree una clase llamada NumeroRacional (fracciones) con
las siguientes capacidades:
a) Cree un constructor que evite un denominador 0 en una
fracción, que reduzca o simplifique fracciones que no estén en
forma reducida y que evite los denominadores negativos.
b) Sobrecargue los operadores de suma, resta, multiplicación
y división para esta clase.
c) Sobrecargue los operadores relacionales y de igualdad para
esta clase.
11.17 Desarrolle la clase Polinomio. La representación interna
de un Polinomio es un arreglo de términos. Cada término
contiene un coeficiente y un exponente, por ejemplo el termino
2X^4
tiene el coeficiente 2 y el exponente 4. Desarrolle una clase
completa que contenga las funciones apropiadas del
constructor y destructor, así como funciones set y get. La clase
también debe proporcionar las siguientes herramientas de
operadores sobre cargados:
a) Sobrecargue el operador de suma (+) para sumar dos
objetos Polinomio.
b) Sobrecargue el operador de resta (-) para restar dos objetos
Polinomio.
c) Sobrecargue el operador de asignación para asignar un
Polinomio a otro.
d) Sobrecargue el operador de multiplicación (*) para
multiplicar dos objetos Polinomio.
e) Sobrecargue el operador de asignación de suma (+=), el
operador de asignación de resta (-=) y el operador de
asignación de multiplicación (*=).
12.3 Muchos programas escritos con herencia podrían
escribirse mediante la composición, y viceversa. Vuelva a
escribir la clase EmpleadoBaseMasComision de la jerarquía
EmpleadoPorComision-EmpleadoBaseMasComision para usar
la composición en vez de la herencia. Una vez que haga esto,
valore los méritos relativos de las dos metodologías para
diseñar las clases EmpleadoPorComision y
EmpleadoBaseMasComision, así como también para los
programas orientados a objetos en general. ¿Cuál metodología
es más natural? ¿Por qué?
12.5 Algunos programadores prefieren no utilizar el acceso
protected, ya que creen que quebranta el encapsulamiento de
la clase base. Hable sobre los méritos relativos de utilizar el
acceso protected en comparación con el acceso private en las
clases base.
12.7 El mundo de las figuras es más extenso que las figuras
incluidas en la jerarquía de herencia de la figura 12.3. Anote
todas las figuras en las que pueda pensar (tanto
bidimensionales como tridimensionales) e intégrelas en una
jerarquía Figura más completa, con todos los niveles que sea
posible. Su jerarquía debe tener la clase base Figura, de la que
se deriven las clases FiguraBidimensional y
FiguraTridimensional. [Nota: no necesita escribir código para
este ejercicio]. Utilizaremos esta jerarquía en los ejercicios del
capítulo 13 para procesar un conjunto de fi guras distintas
como objetos de la clase base Figura. (Esta técnica, conocida
como polimorfismo, es el tema del capítulo 13).
12.9 (Jerarquía de herencia Paquete) Los servicios de entrega
de paquetes como FedEx®, DHL® y UPS® ofrecen una
variedad de opciones de envío distintas, cada una con los
costos específi cos asociados. Cree una jerarquía de herencia
para representar varios tipos de paquetes. Use Paquete como
la clase base de la jerarquía y después incluya las clases
Paquete- DosDias y PaqueteNocturno que se deriven de
Paquete. La clase base Paquete debe incluir datos miembro
que representen el nombre, dirección, ciudad, estado y código
postal para el emisor y el destinatario del paquete, además de
los datos miembro que almacenan el peso (en onzas) y el costo
por onza para enviar el paquete. El constructor de Paquete
debe inicializar estos miembros de datos. Asegúrese que el
peso y costo por onza contengan valores positivos. Paquete
debe proporcionar una función miembro public llamada
calcularCosto que devuelva un valor double indicando el costo
asociado con el envío del paquete. La función calcularCosto de
Paquete debe determinar el costo al multiplicar el peso por el
costo por onza. La clase derivada PaqueteDosDias debe
heredar la funcionalidad de la clase base Paquete, pero
también debe incluir un miem- bro de datos que represente una
cuota fi ja que cobre la compañía de envío por el servicio de
entrega de dos días. El constructor de PaqueteDosDias debe
recibir un valor para inicializar este miembro de datos.
PaqueteDosDias debe redefinir la función
miembro calcularCosto, de manera que calcule el costo
sumando la cuota fi ja al costo basado en el peso, calculado
por la función calcularCosto de la clase base Paquete. La clase
PaqueteNocturno debe heredar directamente de la clase
Paquete y debe contener un miembro de datos adicional que
represente una cuota adicional por cada onza que se cobre por
el servicio de entrega nocturna. PaqueteNocturno debe redefi
nir la función miembro calcular Costo, de manera que sume la
cuota adicional por onza al costo estándar por onza, antes de
calcular el costo de envío. Escriba un programa de prueba para
crear objetos de cada tipo de Paquete y evaluar la función
miembro calcular Costo .
13.3 ¿ cómo es que el polimorfismo le permite programar “ en
forma general”, en lugar de hacerlo “en forma específica”?
Hable sobre las ventajas clave de la programación “en forma
general”.
El polimorfismo nos permite “programar en general” en vez de “programar de manera
específica”. En especial, el polimorfismo nos permite escribir programas que procesen
objetos de clases que formen parte de la misma jerarquía de clases, como si todos
fueran objetos de la clase base de la jerarquía. el polimorfismo trabaja con los
manejadores de apuntadores de clase base y manejadores de referencias de clase
base, pero no con los manejadores de nombres.
Con el polimorfismo podemos diseñar e implementar sistemas que puedan extenderse
con facilidad; pueden agregarse nuevas clases con sólo modificar un poco (o nada) las
porciones generales del programa, siempre y cuando las nuevas clases sean parte de
la jerarquía de herencia que el programa procesa en forma genérica.
13.5 Explique la diferencia entre heredar la interfaz y heredar la
implementación. ¿En qué difieren las jerarquías de herencia
diseñadas para heredar la interfaz, de las jerarquías diseñadas
para heredar la implementación?
La figura 10.27 prueba la clase Interfaz. Observe que sólo se incluye el archivo de
encabezado para Interfaz en el código cliente (línea 7); no hay mención sobre la existencia de
una clase separada llamada Implementacion. Por ende, el cliente nunca ve los datos private
de la clase Implementacion, ni el código cliente se puede volver dependiente del código de
Implementacion.
// Fig. 10.27: fig10_27.cpp 2 // Ocultar los datos private de una clase con una clase proxy. 3
#include <iostream> 4 using std::cout; 5 using std::endl; 6 7 #include "Interfaz.h" //
definición de la clase Interfaz 8 9 int main() 10 { 11 Interfaz i( 5 ); // crea un objeto Interfaz
12 13 cout << "Interfaz contiene: " << i.getValor() 14 << " antes de setValor" << endl; 15
16 i.setValor( 10 ); 17 18 cout << "Interfaz contiene: " << i.getValor() 19 << " despues de
setValor" << endl; 20 return 0; 21 } // fin de main
Figura 10.27 | Implementación de una clase proxy.
Interfaz contiene: 5 antes de setValor Interfaz contiene: 10 despues de setValor
13.7 Explique la diferencia entre la vinculación estática y la
vinculación dinámica. Explique el uso de las funciones virtual y
la vtable en la vinculación dinámica.
13.9 Sugiera uno o más niveles de clases base abstractas para
la jerarquía de Figura que vimos en este capítulo, y que se
muestra en la fi gura 12.3. (El primer nivel es Figura, y el
segundo nivel consiste en las clases Figura Bidimensional y
Figura Tridimensional.)
13.11 Se le ha pedido que desarrolle un simulador de vuelo que
tenga salidas gráficas elaboradas. Explique por qué la progra-
mación polimórfica podría ser especialmente efectiva para un
problema de esta naturaleza.
13.13 (Jerarquía de fi guras) Implemente la jerarquía de Figura
diseñada en el ejercicio 12.7 (que se basa en la jerarquía de la fi
gura 12.3). Cada FiguraBidimensional debe contener la función
getArea para calcular el área de la fi gura bidimensional. Cada
FiguraTridimensional debe tener las funciones miembro
getArea y getVolumen para calcular el área superfi cial y el
volumen, respectivamente, de la fi gura tridimensional. Cree un
programa que utilice un vector de apuntadores Figura a objetos
de cada clase concreta en la jerarquía. El programa deberá
imprimir el objeto al cual apunta cada elemento del vector.
Además, en el ciclo que procesa a todas las fi guras en el
vector, determine si cada fi gura es FiguraBidimensional o
FiguraTridimensional. Si es FiguraBidimensional, muestre su
área. Si es FiguraTridimensional, muestre su área y su
volumen.
13.15 (Jerarquía de herencia Paquete) Use la jerarquía de
herencia Paquete creada en el ejercicio 12.9 parea crear un
programa que muestre la información de la dirección y que
calcule los costos de envío para varios objetos Paquete. El
programa debe contener un vector de apuntadores Paquete a
objetos de las clases PaqueteDosDias y PaqueteNocturno. Itere
a través del vector para procesar los objetos Paquete mediante
el polimorfismo. Para cada Paquete, invoque a funciones get
para obtener la información de las direcciones del emisor y del
receptor, y después imprimir las dos direcciones como deben
aparecer en las etiquetas de envío. Además, llame a la función
miembro calcularCosto de cada Paquete e imprima el
resultado. Lleve la cuenta del costo de envío total para todos
los objetos Paquete en el vector, y muestre este total cuando
termine el ciclo.