How can inheritance break encapsulation if we only use protected and private access modifiers in the superclass?
It is sometimes claimed inheritance exposes the superclass implementation. Surely this is not true if the member variables are declared as private? If this refers to changes being made in the superclass will break the subclass, couldnt this affect non-inheritance too?
I also fail to see how composition is any different, with regards to exposing the underlying implementation? We can only use public functions using the composition approach- surely this exposes more?
A deriving class can have access to parts of the implementation of the base class. Eg. if you used protected for any or all members in the base class then the base class would it self be unable to enforce it’s own invariants. This could break the functionality of the base class. Changing the name of a field or removing or adding one might cause issues for the deriving class unless they are private, so again exposing the implementation might break the otherwise correct code.
The template pattern is a deliberate way of exposing part of the implementation of the base class, that it’s deliberate does not mean it’s not exposing (parts of) the implementation. Using composition (strategy) to get the same rsult (usually related to open/closed principle) has a looser coupling.
E.g. if you change the signature of one of the virtual methods (e.g. the name) or add a new (abstract) method used in the template pattern that change cascade to all deriving classes. In the case of composition you can change the name of all the methods in the class that does the composing without changing any of the classes you compose from. You can also add another step to the algorithm with out changing the other classes (as long as one of the parts you compose from already supports this functionality)
A different way of looking at why virtual methods can break encapsulation:
Take this class
In the above example we can be sure that the implementation of Print will not result in an index out of bounds (thread safety aside) and that all elements of the array will be printed (unless Console.WriteLine or string.Fromat fails). If however we change the signature of CanContinue to the below
There’s no longer any gaurantee that ArrayPrinter will work correctly. We’ve made it possible to change the implementation of Print from the outside of the class and hence have broken encapsulation. SOme might argue you only break encapsulation if you expose your fields. I don’t share that oppinion the below code suffers the exact same problem as the above, though it’s exposing a Field (through a property, just to show that hidding you’re fields behind a property doesn’t ensure that you haven’t broken encapsulation)