Veamos:
Código:
pago(float const cantidad) : Cantidad(cantidad);
Por explicarlo fácilmente, eso asigna a la __constante__ Cantidad de la clase (private) el valor del parámetro. Dentro del código del constructor es mejor poner eso que:
Código:
pago::pago(float const cantidad)
{
Cantidad = cantidad;
}
Primero, porque es mucho más efectivo. Segundo, porque permite asignar el valor a la constante (tienes asegurado que la cantidad no va a cambiar nunca). También puedes hacerlo aunque no sea constante.
Eso es para establecer que la clase es virtual - forzar polimorfismo - (virtual) y pura (= 0). Se coloca muchas veces en el destructor para no ponerlo en otras funciones. Realmente al destructor no le afecta.
El destructor derivado siempre se va a llamar antes que el base. Si tienes una caja llena de bombones, luego metes una madera y encima los caramelos. Para volver "hacia" atrás, debes sacar los caramelos, luego la madera y luego los bombones. En resumen: se llama primero al destructor derivado, luego al base. Pero eso es automático y _no tiene que ver_ con "virtual" o "= 0".
Para que te aclares, lo de "virtual" y "= 0 " no "va" con los constructores/destructores. Se coloca en el destructor para no tener que usar una función basura que simplemente tenga esos atributos.
Un constructor es lo mismo. Siempre se llamará al derivado y luego al base. Para hacerlo, se usa:
Código:
pago_dinero(float const cantidad) : pago(cantidad);
Eso lo que hace es llamar al constructor de la clase base "pago(float)" y le pasa como argumento el mismo que el que le has pasado (dado que lo lógico es que si realizas un pago el dinero que pongas será el mismo que si lo haces con dinero, por lo menos el dinero "dado", sin impuestos
). Por eso te sugerí que en ese contructor también puedes implementar (y es la utilidad en este caso que veo) algo así:
Código:
pago_tarjeta(float const cantidad, tarjeta tar) : pago(cantidad);
En el código de la función lees la tarjeta, cobras los impuestos... Lo que sea, y encima sin alterar otro tipo de pagos (como el del dinero a secas). Así, harías (es un simple ejemplo):
Código:
{
int precio = 1000;
char respuesta;
int tarjeta_ID;
tarjeta * T;
cartera mi_cartera(10000);
cout << "El articulo cuesta " << precio << endl;
cout << "Paga con tarjeta? S/N" << endl;
cin >> respuesta;
if(respuesta=='N'||respuesta=='n')
{
pago_dinero p1(mi_cartera);
if(p1.problema!=NULL)
{
cout << p1.problema << endl;
return;
}
cout << "Pago realizado en metalico" << endl;
return;
}
else if(respuesta=='S'||respuesta=='s')
{
cout << "Su numero de tarjeta por favor? " << endl;
cin >> tarjeta_ID;
// Tambien puedes practicar con algo automatico como:
// tarjeta_ID = mi_cartera.tarjeta.ID;
// Dado que una persona sabe sacar la tarjeta y mirar el numero..
// La imaginacion es el limite.
T = ObtenerTarjeta(tarjeta_ID);
pago_tarjeta p2(precio,T);
if(p2.problema!=NULL)
{
cout << p2.problema << endl;
return;
}
cout << "Pago realizado con la tarjeta " << *T << endl;
}
else
{
cout << "No le he entendido" << endl;
}
}
Suponiendo que tenemos una clase tarjeta creada y funcional al igual que una cartera... (Es tan solo un ejemplo aplicado, para que veas como se puede programar) En ese caso también sería bueno añadir el control de saldo y demás en la propia clase.
Date cuenta de que lanzo el pago, y la clase lo comprueba todo. En cualquier caso, la clase derivada debe rellenar un supuesto campo "problema" que es un puntero a una cadena si hay algún problema, y si no dejarlo en NULL. Este campo debe estar en la clase base, porque es común a cualquier pago, no así el problema que pueda surgir (tarjeta no valida, dinero insuficiente...) etc.
Para hacer:
Código:
cout << "Pago realizado con la tarjeta " << *T << endl;
debes sobrecargar el operador << de la clase ostream como friend... Es para mostrarte el mundo infinito que tiene C++ ;) (PD: "Los operadores sobrecargados no sirven para nada" by Blackwind)