Quando inserisci una lettera e cerchi di leggere come numero lo stato dello stream viene impostato a fail, e i caratteri "errati" rimangono nel buffer di input. Pertanto devi ripristinare lo stato dello stream (cin.clear()), svuotare il buffer dai caratteri errati (cin.ignore(numeric_limits<streamsize>::max(),'\n' );) e tornare a prima dell'inserimento (cosa che puoi fare facilmente con un while e un flag).
Per evitare tutta questa trafila ho scritto queste funzioni template che si smazzano da loro il problema; metti questo codice in un file a parte, diciamo AcquireInput.hpp
codice:
#ifndef ACQUIREINPUT_HPP_INCLUDED
#define ACQUIREINPUT_HPP_INCLUDED
#include <iostream>
#include <limits>
#include <string>
template<typename InType> void AcquireInput(std::ostream & Os, std::istream & Is, const std::string & Prompt, const std::string & FailString, InType & Result)
{
do
{
Os<<Prompt.c_str();
if(Is.fail())
{
Is.clear();
Is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
Is>>Result;
if(Is.fail())
Os<<FailString.c_str();
} while(Is.fail());
}
template<typename InType> InType AcquireInput(std::ostream & Os, std::istream & Is, const std::string & Prompt, const std::string & FailString)
{
InType temp;
AcquireInput(Os,Is,Prompt,FailString,temp);
return temp;
}
/* Usage example:
//1st overload
int AnInteger;
AcquireInput(cout,cin,"Please insert an integer: ","Invalid value.\n",AnInteger);
//2nd overload (more convenient, in this case)
int AnInteger=AcquireInput(cout,cin, "Please insert an integer: ","Invalid value.\n");
*/
#endif
e #includilo nel tuo sorgente; potrai quindi usare le funzioni in questione come da esempi (ci passi cout come stream di output, cin come stream di input, il messaggio di "richiesta dati" come terzo argomento e quello di errore come quarto).