This uses an initialisation list, to initialise radius to the value of r. The moment the Circle object is instantiated, radius will have that value.
I assume your second example is supposed to be:
Circle(double r) {radius = r;}
This sets the value of radius to be r, but does so after the Circle object has been constructed. Technically, when the object is constructed, radius is initialised with its default value (if it has one; otherwise its initial value is undefined). Then, as the constructor executes, it assigns the value of r to radius.
It's the same as the difference between:
double r = 1.2345;
and
1 2
double r;
r = 1.2345;
For simple types of variable, like double, it doesn't really matter. But when the data members are objects, rather than simple types, it can make a difference.
In the first one, you're trying to assign a double (r) to a Circle. There is a way to get this to be valid, but it thankfully isn't valid by default. Such implicit conversions can be error-prone.
In the second, one you're calling the constructor for Circle that takes in a double as a parameter.
What do you mean by "doesn't work"? What doesn't work? Does it not compile? Does it compile but crash? Something else?
Give us all the information you have about your problem, so that we can help you more easily.
I assume this is about the initialisation of the base member?
base(r)
This is initialisation. It invokes the appropriate constructor for the Circle class. You've written a constructor Circle(double r), so that gets called to initialise base.
base = r;
This is a assignment. You haven't written an overloaded assignment operator that takes a double, so the compiler has no idea what it means to assign that value to a Circle object.
This is a perfect example of why I said:
But when the data members are objects, rather than simple types, it can make a difference.