Why C implements methods as non-virtual by default?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
C# methods are non-virtual by default because virtual dispatch is a design choice, not the safest universal default. Making methods virtual opens an inheritance contract: derived classes can override behavior, base classes must tolerate that, and future changes become more constrained. C# therefore requires the programmer to opt into virtual behavior explicitly.
Virtual Methods Are an API Commitment
When a method is marked virtual, you are not only enabling polymorphism. You are promising that derived classes may replace that behavior and that your base class design can handle it safely.
That is useful when extensibility is part of the design. But it also means the base class author must think about override safety, call order, invariants, and documentation.
If every method were virtual automatically, many APIs would expose extension points they never intended to support.
Non-Virtual by Default Supports Encapsulation
Most methods are implementation details, not variation points. Keeping them non-virtual by default protects internal logic from accidental override and makes class behavior easier to reason about.
This communicates a simple contract: callers can use the method, but derived classes are not expected to redefine the calculation.
That default helps developers expose only the extension points they mean to support.
Versioning Is Easier When Methods Are Closed
Virtual methods complicate versioning. Once a method is overridable, later changes to how and when it is called can break subclasses in subtle ways. Base-class evolution becomes harder because derived classes may depend on behavior that was never meant to be externally customized.
Non-virtual defaults reduce that fragility. Library authors can later decide to make a method virtual if they intentionally want to open that seam. The reverse direction is much harder.
This is closely related to the classic fragile-base-class problem: inheritance creates coupling between base and derived classes that is hard to reason about across versions.
Performance Is a Secondary Reason, Not the Main One
Non-virtual calls can sometimes be optimized more aggressively than virtual calls, and historically that mattered more. Modern runtimes can devirtualize in many situations, so raw dispatch speed is not the main design argument.
The stronger reason is semantic clarity. C# wants virtual to mean something deliberate. A reader of the code should be able to spot where polymorphic substitution is expected.
Prefer Composition Unless Inheritance Is Intentional
One reason this language design works well is that many customization problems are better solved with interfaces, delegates, or composition instead of overrides.
This avoids turning every method into an inheritance hook. The design is explicit about what varies.
Common Pitfalls
- Assuming methods should be virtual by default because inheritance is available.
- Exposing virtual methods without documenting the override contract or preserving class invariants.
- Using inheritance for customization when composition or interfaces would create less coupling.
- Treating performance as the only reason for non-virtual defaults.
- Forgetting that virtual methods constrain how a base class can evolve over time.
Summary
- C# uses non-virtual methods by default so overridability is explicit, not accidental.
- A virtual method is an extensibility contract, not just a dispatch mechanism.
- Closed methods are easier to reason about, version, and maintain safely.
- Performance matters, but API design and inheritance safety matter more.
- Mark methods
virtualonly when overriding is a deliberate part of the class design.

