Ad-hoc polymorphism is interfaces in java, typeclasses in haskell, implicits in scala etc.
Classes (usually) enable subtype polymorphism.
The distinction is how polymorphic code is written not what the semantics can be expressed. E.g. rust traits allow for dynamic dispatch. While there is a distinction between ad-hoc polymorphism and subtype polymorphism, I don't believe it is necessary when comparing what semantics FP and OPP languages express.