Overloading can only be done by varying the argument list. The return type must be the same.
That is not quite correct.
The argument list must be different, but return types can be anything, the limitation is when using pure virtual functions, not virtual functions.
If a base member has a certain prototype, a user can expect a certain functionality in derived types, so it is perfectly valid for a common base set of overloads to return different types.
It is not 'valid' when the overload introduces uniqueness into the derived types, and a unique member should be used rather than an overloaded member.