Actually, it's been addressed many times. I've answered this question several times myself. Unfortunately, the internet is rather large, so finding anything on it can be rather difficult, especially when there isn't really an exact set of keywords that applies. So don't worry about it.
For your isIsosceles() thing, you can apply the same technique as you did for getRadius(). What function calls isIsosceles()? Why does that function call that on an element in an array of shapes? Whatever functionality needs to know whether the shape is isosceles is specific to triangles, and so you have to question why it is being called with your shape array and not as part of the triangle interface.
When designing public inheritance, it is best to focus on making sure that the derived classes work like a base class. In other words, anywhere that you have a base class, all the derived classes will work as well. If you are using the WhatAmI approach, then you have some objects that can check for Isosceles and others that cannot, and they all come from the same collection of base class pointers.
There are times when WhatAmI is appropriate. I've used that myself in both good designs and bad ones. The bad ones were hard to maintain, as I ended up with lots of switch statements and if/else clauses and tons of duplicated code. The good ones ended up using WhatAmI or dynamic_cast as part of a double dispatch system that is necessary when a function between two objects depends on the dynamic type of each (my example was sorting, where sometimes type mattered in the sort).
When I made the bad design, I didn't really know that it was that bad, but even if I did I probably would have done it anyway because it was an extension of existing code that would have been difficult to change. Now, after maintaining and expanding that code for years and having more headaches with the parts implemented via WhatAmI, I wish I could go back and change it. But, the best I have time for now is to not make the same mistake again.
Good luck!