There is no need for complicated statements.
You just need to understand that IO operation notice, when there was a problem. And then they set failure bits, which you can check.
Please look in the CPP reference at this link. There is a long description of what could happen and what failure bit will be set and how it can be tested.
So, if you use for example the stand extraction operator >> like in std::cin >> radius then this operator will try to read a value from the console and convert it to a double. If it cannot do that, because you entered for example "abc" instead of a number, a failure bit will be set. The std::cinis then in state fail and does not work any longer.
If you want to continue to use std::cin then you must clear the fail bits with the clear() function. So, you need to write std::cin.clear();.
But this is not sufficient. There might be still some other characters in the input buffer. And those need to be removed. Imagine that you enter "XYZ" instead of a number, then std::cin will go into failure state after reading the first character 'X'. We need to eliminate all the wrong characters, because otherwise, they will be read again with the next >> operation.
For this we have the function ignore. Please read here about the function and look at the example at the bottom of the page. Exactly what you need.
Next: How can we check for an error of an IO operation?
You may have heard that we can chain IO operations. For example: int a,b; std::cin >> a >> b; or, for the output case std::cout << value << "\n";
Why does this work? You need to understand the the extraction and inserter operator >> and << return a reference to the stream for which they have been called.
So, std::cin >> a; will return a reference to std::cin. And that is the reason why you can chain IO operations.
std::cin >> a >> b; will first do std::cin >> a which will return std::cin. The rest of the expression will now be std::cin >> b;. also this will be performed and again std::cin will be returned.
And this we can use. The basic:ios has 2 operators to check the failure state.
- the bool operator
- the not operator !
So, you can check the state of std::cin simply with if (std::cin). And because the if-statement expects a bool expression, it will call the streams bool operator. And with that get the state.
And now, what we learned above: if (std::cin >> a) will try to read a value into "a" then return std::cin and then its bool operator is called.
Now we found a possibility to check for a correct IO operation with if (std::cin >> radius) But of course we can do more test in the if statement. You have often seen and && or or|| operators in conditions. You can make use of it. And especially you can make use of boolean shortcut evaluation.
Meaning, if the outcome of a condition is already clear by evaluation the first term, then the second term will not be evaluated.
So, we can write if ((std::cin >> radius) and (radius > 0.0)) to check for a valid input. If the reading of the input fails, then the check for greater than 0 will not be executed. It will only be executed, if the input was successful.
With all the above, we can now draft the below very simple solution:
#include <iostream>
#include <limits>
int main() {
    double radius = 0.0;
    bool valueOK = false;
    while (not valueOK) {
        std::cout << "\n\nInsert radius. A positive value: ";
        if ((std::cin >> radius) and (radius > 0.0))
            valueOK = true;
        else {
            std::cout << "\n\n***Error: invalid input\n";
        }
        std::cin.clear();
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    }
    const double PI = 3.14159265358979323846;
    std::cout << "\n\nSphere Radius:\t" << radius
        << "\nSphere area:\t" << 4.0 * PI * radius * radius
        << "\nSphere volume:\t" << 4.0 / 3.0 * PI * radius * radius * radius << '\n';
}
No need for complicated statements.