Thank you Onigiri Flash for the illustrations, they really helped! I like both ideas, but Onigiri's seems more practical in my case because controlling the boat might change. For example, I'm going to have a row boat that requires a constant press to keep moving and speed boat that can move by holding a button.
But I might do both if I'm going to have many boats in different subclasses.
While that can work if your game is small, as it grows it becomes much more difficult to control.
You've got Boat, StarterBoat, MegaBoat. Seems reasonable from your view.
Let's say you build a FlyingBoat, and a TurboBoat. Those would make good subclasses.
Then lets say you want a bigger cannon on a MegaBoat, so you make MegaBoatBigCannon, MegaBoatSmallCannon, MegaBoatMediumCannon.
Sooner or later you're going to want a combination of them. A StarterTurboBoat. or a FlyingMegaBoat. Or a FlyingMegaBoatSmallCannon.
When you end up wanting to share different combinations of features between a different distribution of objects, suddenly the inheritance tree breaks down terribly. You end up duplicating code between classes since you cannot easily pull from multiple base classes. Everything breaks down, and you have some really hard days trying to make your system work.
Inheritance is something beginners tend to overuse when they discover it. It's good that you've discovered it, but just be careful. You've discovered how to use hammer, don't let everything become a nail.
It is far better to create an interface that will work for all boats, much as you described. Then whenever you use the object, refer to it by the interface it implements rather than the concrete type. The practice is called the Dependency Inversion Principle, which has lots of good reading around the Internet. I suggest you study up on it.
Inheritance is useful to modify the internal behavior without modifying external behavior or external interfaces. That is not what you are describing with your boats. Instead you are talking about modifying values of instances.
Modifying values is best accomplished through changes to data, not subclasses. If you can change values through math formulas or values stored in data tables, it is probably not good for inheritance. Use inheritance only when you are changing a large behavior. For instance, maybe you need one type of boat to call a completely different function for collision handling. Often you can still do that through a data table, but sometimes it is better done with inheritance through code.
Use Inheritance when it implements a perfect "IS A" relationship. Any action you do on one inherited type should be perfectly interchangeable with any other subclass. If you could say "HAS A" or "USES A", it should composition instead.
If properties are changing, as opposed to behavior, then there is no need to subclass.
In your case, a boat has top speed, a boat has size, a boat has a steering function, a boat has a collision function. These are all properties that are changing, not object behavior. So all of these should be different instances of data, not new classes.