Formally, each class has an implicit property called class invariant. It's the assumption you can always make about each object instantiated using that class.
In practice, we must ensure each object is valid - invariant is satisfied - and you can guarantee this only by taking each modification attempt and verify it transitions your object to another valid state.
Of course, you cannot do that on stuff that is directly assignable. So, as above, public members are "don't care".
In line of concept, you should use private on all other cases. But in reality protected is often a good compromise, due to specificity of derived class code - if someone is writing a derived class, he has to deal with much more focused context than the whole program. Someone think protected is bad and to a certain degree I agree with them but in the real world, I find it very convenient.
Edit: derided class code... what a typo!