Why are begin() functions needed to initialize hardware (if they are)?
It's all to do with the order of execution.

Constructors are executed before normal functions. That includes the main() function which eventually calls setup() and (repeatedly) loop(). One of the other things that main() does is call init() (or some variant of) which configures the hardware.

Since that happens after any global constructors have been run anything that the constructor did to the hardware could potentially be undone.

Thus it is normal to defer any hardware configuration until after main() has done the work of setting things up, and the convention is to use a begin() function to do it.