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]); } } }