My answer, in addition to Solution 1, is mainly in my comment to that solution.
I would like to reiterate: the question is not really adequate in the following sense: it apparently assumes that OOP concepts can be chosen in one or another combination, for best results. This is not really the case. For example, you can build some design on the combination of generics (non-OOP concept also available in some non-OOP languages, such as first version of Ada) and OOP. Then you really have choice.
Inside OOP there is only one choice: to use OOP or not (again, not mentioning interfaces, multiple inheritance and also delegates, which really gives the choice; let's assume you have OOP without those feature, just for the sake of discussion). Not using OOP using a pure OOP language may mean different approaches, but is possible when one uses classes formally, not leveraging OOP power in any way. How? One can use only static methods, never virtual ones, not even instance non-virtual methods (in some languages, static methods can be abstract/virtual, quite naturally). That would be 100% equivalent to having old "structured language" without a glimpse of OOP. Even if one uses inheritance, instance methods, it does not make the use of the OOP technology. And finally, some especially silly "developers" even use the keyword "virtual", but not really leverage "virtuality". Such programs could be logically equivalent to the same programs with the words "virtual" removed. I really saw such things. :-(
The technology uses OOP when late binding is really used and leveraged. Alternative approach using interfaces, with or without abstract/virtual/override, can also be considered OOP. But other concepts are not the subject of choice. If OOP power is really leveraged, all other "concepts" are not optional ones, they are needed to support the central ones. There is no any late binding and/or polymorphism without, say, encapsulation and inheritance — otherwise there would be nothing to "bind".
(By the way, not many people who actually can leverage OOP power understand the possibility of polymorphism based on interfaces and not base class. Frankly, I got it much later myself.)
These considerations, perhaps, illustrate the weakness of OOP pedagogic in general. The traditional approach tends to tread the mentioned "concepts" as "equal", which creates some illusions in those who did not grasp the main idea. As I can observe, such people even manage to graduate and start working, having no idea how OOP works, but able to tell us "correct words" about those concepts. This is pretty sad.
[EDIT]
I forgot to address one thing. "Overriding" is really an OOP concept. So called "overloading" is not. The second concept does not deserve a separate name itself. This is one of the worst and confusing term which misleads too many people in whole industry.
The "term" is very confusing: it hardly could be called "overloading", because nothing is "loaded". It merely means that the syntax allows completely different formally unrelated methods to have the same name. Pretty trivial thing. A compiler can distinguish them by profile inferred from the call code. Or not; then the compilation error is issued. OOP is not needed to have this trivial feature.
—SA
Updated 24-Sep-14 7:57am
v3
Code reuse is a general target of OOP and (theoretically) all the three pillars of OOP, namely Encapsulation, Inheritance and Polymorphism support it. Practically code reuse is almost a myth: in order to be reusable a piece of software must solve a rather general problem and be very careful coded (requiremts fulfilled, for instance, by a design pattern).