1

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?

2
  • 2
    The inheritance relationship is 'tighter' than the composition relationship. The child class is tightly coupled to the implementation of the parent class (i.e. you inherit a specific implementation). To put it another way you can't inherit an interface (and gain the appropriate functionality), but you can compose one. It's up to you how big a deal this is, sometimes tight parent/child relationships are appropriate. Commented Feb 27, 2012 at 11:14
  • Are you aware of the fragile base class problem? Commented Feb 27, 2012 at 11:25

3 Answers 3

3

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

class ArrayPrinter{ private bool CanContinue<T>(T[] array, int newIndex){ return newIndex<array.Length; } public void Print<T>(T[] array){ for(var i = 0;CanContinue(array,i);i++){ Console.WriteLine(string.Format("{0}",array[i]); } } } 

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

 protected virtual bool CanContinue<T>(t[] array, int newIndex) 

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)

class ArrayPrinter<T>{ private Func<T[],int,bool> _canContinue; protected Func<T[],int,bool> CanContinue{ get{ return _canContinue ?? canContinue; } set{ _canContinue = value; } } private bool canContinue(T[] array, int newIndex){ return newIndex<array.Length; } public void Print<T>(T[] array){ for(var i = 0;CanContinue(array,i);i++){ Console.WriteLine(string.Format("{0}",array[i]); } } } 
Sign up to request clarification or add additional context in comments.

5 Comments

In your first example, you correctly say a virtual function means we cannot be assured the code would work. I am not saying you suggested composition, but many people do suggest it to fix this. Assume we have a delegate and ArrayPrinter.CanContinue() calls delegate.CanContinue(). I fail to see how composition would provide better assurances of method safety? I still may not be able to see the source code of the delegate function delagte.CanContinue()?
was that last word meant to say "cant"? :)
@user1107474 a delegate is not composition. So I'm unsure why you talk about it. The difference between composition and inheritance (in this case) is that when using inheritance the deriving classes can break the base class if the encapsulation is broken even if the base class is implemented correctly and the base class can't ensure the invariants of it self. Using composition it can because nothing but it self has access
would your argument also support delegation being preferred over inheritance?
@user1107474 delegation is less akin to inheritance than composition (most compilers actually uses a kind of composition to achieve inheritance). You could say that the strategy is a kind of delegation and when using composition you also use delegation but you can use delegation without composition and that's a completely different debate than this one
1

The inheritance does not break the encapsulation as it is also stated in the SOLID pricniples in this case you should have a look at the Open/Close principle:

The Open / Closed Principle (OCP) states that classes should be open for extension but closed for modification. "Open to extension" means that you should design your classes so that new functionality can be added as new requirements are generated. "Closed for modification" means that once you have developed a class you should never modify it, except to correct bugs.

more info at: http://www.blackwasp.co.uk/SOLIDPrinciples.aspx

4 Comments

using either virtual methods or protected modfiers can expose the implementation of the super class so your first statement is incorrect
if a super-class contains a virtual method it means that who has designed that class wants to allow the user to override the behavior of that method and you won't break any encapsulation.
@Rune, can you elaborate? If I use protected for functions and private modifiers for variables how can the implementation be exposed?
See my answer for why virtual methods can break encapsulation.
-2

Access modifiers is sometimes needless. If you are writing a small application using OOP, the only coder is yourself, then you just use public access modifiers.

If you want to make code more clear for yourself, of you'd share your code with others and you want to tell them some methods or member variable need different treatments, then use protected or private access modifiers.

I think It's no good to be confused by such problems. In some new programming languages, it just no need to use access modifiers.

4 Comments

In programming languages where access modifiers exist it is a best practice to use access modifiers. You can never know when you'll need to share the code with others or extend a small project into a large one. Use the language idioms. They exist for a reason.
access modifiers does not only 'protect' your code from others, but from yourself too. it's much easier to maintain a well designed system, even if you are the only one who ever sees that code.
thanks for your comments, maybe my words was beyond my idea. While, when you are confusing which access modifier should be used, what to do?
@BrentJiang always choose the most strict access modifier, except when you have a clear reason to expose more information to the outside world.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.