Skip to main content
Post Made Community Wiki
Source Link
Pavel Minaev
  • 102k
  • 27
  • 222
  • 293

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...