OK, the general rule of thumb is, when dealing with a ReferenceCount object, you should use an ordinary pointer only if you are confident that there is a PT(object) that is also holding the pointer somewhere else, and that that PT(object) will persist for at least the lifetime of your ordinary pointer. If you have any doubt at all, you should use a PT(object).
In Panda examples where you see the method returning an ordinary pointer, these are generally accessors into the PT(object) that is already stored within the class, so it’s safe to return an ordinary pointer. However, in cases where the object has been newly constructed and is not stored anywhere, you will see the Panda method returning a PT(object). For instance, PartBundle::bind_anim() returns a PT(AnimControl), because that AnimControl was newly created and is not stored anywhere in the class.
In general, when receiving a parameter into a function, it’s safe to receive an ordinary pointer, because the caller must have it stored in a PT(object) somewhere that will persist for at least the lifetime of the called function.
Also, when you first create a new ReferenceCount object, you should generally always store it immediately in a PT(object), because initially its reference count is zero, and it is in danger of getting accidentally deleted if you do anything with it without first storing it in a PT(object).
Once it is stored in a PT(object), you need to ensure that there is at least some PT(object) somewhere in the world that is always storing it, until is is no longer needed.
To answer your specific questions:
(1) Use PT(object) everywhere, whenever you want to store the pointer. For just passing pointers around, use either ordinary pointers or PT(object) pointers, according to whether you are confident the reference count is already stored elsewhere or not. If you have any doubt, use PT(object) pointers.
(2) You should never explicitly delete pointers to ReferenceCount-inherited objects. That is certain to cause a double-delete, since the reference-counting system will delete it automatically when the reference count is decremented to zero. You should also not explicitly decrease reference counts. Instead, store the object in a PT(object) pointer within your class, and let the reference-counting system work automatically, the way it is supposed to.
(3) No, this will be bad, because there is no PT(object) anywhere holding on to the object. In this case you should return a PT(FooBar) instead of FooBar *. Other than that the function can remain as-is, though if you wanted to modify the function to do anything at all with your new FooBar object before returning it, you should be careful to store it in a temporary PT(FooBar) when you construct it (and not an ordinary FooBar *).
(4) Sure, we do this all the time. For instance, lots of things inherit from ReferenceCount (or some derivative), and Namable. But your new derived class is now a ReferenceCount object, and must be treated like a ReferenceCount object, meaning store it in a PT(object) pointer, and never delete it explicitly.