String-based Data Validation Works BetterInstead of relying on a field's datatype, read all the values as strings and test them. A valid number of passengers, for example, should only contain digits. The revised get_details() function now looks as follows:
#include <algorithm>
void booking::get_details()
{
string num;
bool kosher=false;
cout<< "enter number of passengers: "<> endl;
cin>>num;
//make sure that num contains digits exclusively
if(find_if(num.begin(),num.end(), nondigit())==num.end())
kosher=true; // we have a valid string
else
// we have an invalid string
}
The interesting part is the find_if() call. The algorithm find_if() defined in <algorithm> takes three parameters: two input iterators that mark the sequence's beginning and end, respectively and a predicate. Our predicate can be an address of a function, say isalpha() or it can be a function object whose overloaded () operator returns bool. For each character in the string num, find_if() calls the predicate. If any of the characters isn't a digit, find_if() returns an iterator pointing to the first non-digit character. Otherwise, it returns a value equal to the second argument. In other words, the user's input is kosher if find_if() returns num.end().
The nondigit function object uses the standard function isdigit() declared in <cctype>. It negates the result of isdigit() and returns it:
class nondigit
{
public:
bool operator() (char c) {return !isdigit(c);}
};
If the string is kosher, we can proceed to the next step, namely converting it to int. We use a stringstream object for this:
if(kosher==true)
{
stringstream s(num); //insert string to s
s>>passenger; //extract int value and write it to passenger
}
In case of an invalid string, we can display a detailed error message to the user, possibly highlighting the first invalid characters in the entered string.