First an aside: Get a good book. Read that book. I wandered into C++ thinking 15 years of C and 8 years of Java taught me everything I needed to know about C++. Laugh at my hubris. Laugh. LAUGH! But learn from it. I still run over the garbage code I wrote during those few years before someone loaned me a copy of Meyers' Effective C++ and I started to learn C++.
I cringe. I fix the bugs. I carry on.
C++ IO idioms are not that different from C. Always check the return code. Always validate the input before using it. Don't eat the yellow snow. Most of it is common sense.
But... C++ type checking is anally retentive and the functions are completely different. Often they're buried in overloaded operators that know exactly what to do with the type you're passing. Now you get a compiler error instead of a warning (if you're lucky) when you try to write something unexpected.
Here's a quick cut of how I'd implement the questioner's C code. Comments are embedded to explain some of the decision-making where it makes the most sense to do it.
#include <iostream>
#include <string>
int getInt(std::istream & in) // with a generic istream we can read just about
// anything with the same code. Function is
// instantly much more reusable
{
while (true) // but realistically you do want some sort of exit if only to
// allow the program to politely exit
{
std::string line;
if (std::getline(in, line)) // read the whole line so we don't have
// to find and throw anything way later.
// Always check for success. ALWAYS.
{
try
{
size_t pos; // will be updated to show where the integer stopped.
int result = std::stoi(line, &pos, 10); // convert to base 10
if (pos == line.length()) // If the integer and the string end
// in the same spot, you a good number
{
return result;
}
}
catch (const std::invalid_argument &) // got total garbage.
{
}
catch (const std::out_of_range &) // got too big a number
{
}
//Any other exceptions are unexpected here. Let them through to be
// caught by someone who can deal with them.
// That said, I usually use C's strol function instead of std::stoi
// to avoid the exception overhead. User typo is NOT exceptional
// enough to be worth exceptions in my book.
// On the other hand, if you're waiting for user input, who gives a
// smurf about speed? Users are sssssssllllllooooowwwwwww...
}
else
{
// stream is probably broken. Good place to throw an exception.
}
}
}
// getIntInRange function definition goes here:
int getIntInRange(std::istream & in, int min, int max)
{
while(true)
{
int value = getInt(in);
if (value < min || value > max)
{
std::cout << "*** OUT OF RANGE *** <Enter a number between "<< min << " and "<< max << ">: ";
}
else
{
return value; // returning here. Why test the bounds twice?
}
}
}