This one was very non-obvious when I discovered it, especially in light of the difference with the same situation for interfaces. It's not a break at all, but it's surprising enough that I decided to include it:
Refactoring class members into a base class
Kind: not a break!
Languages affected: none (i.e. none are broken)
API before change:
class Foo { public virtual void Bar() {} public virtual void Baz() {} } API after change:
class FooBase { public virtual void Bar() {} } class Foo : FooBase { public virtual void Baz() {} } Sample code that keeps working throughout the change (even though I expected it to break):
// C++/CLI ref class Derived : Foo { public virtual void Baz() {{ // Explicit override public virtual void BarOverride() = Foo::Bar {} }; Notes:
C++/CLI is the only .NET language that has a construct analogous to explicit interface implementation for virtual base class members - "explicit override". I fully expected that to result in the same kind of breakage as when moving interface members to a base interface (since IL generated for explicit override is the same as for explicit implementation). To my surprise, this is not the case - even though generated IL still specifies that BarOverride overrides Foo::Bar rather than FooBase::Bar, assembly loader is smart enough to substitute one for another correctly without any complaints - apparently, the fact that Foo is a class is what makes the difference. Go figure...