일단 상업적으로 가장 활발히 이용되고 있는 Java와 C#의 예를 들어보자. Java에서 instance method는 final로 선언되지 않은 이상 모두 virtual이다. 반대로 C#에서는 virtual로 선언하지 않는 이상 모두 non-virtual method이다.
Java의 후발주자격인 C#이 모든 instance method는 default로 non-virtual이 되게 한 데에는 몇 가지 이유가 있다. C# 개발자 주 아키텍터(lead architect)인 Anders Hejlsberg는 다음과 같은 이유를 들었다.
첫 번째 이유는 성능(performance) 때문이다. virtual method는 해당 instance의 runtime type을 check 후에 virtual method table을 참고해서 해당 method를 dispatch 한 후에 호출하므로 non-virtual method보다 overhead가 크다. 일반적인 Java 프로그래머들은 virtual일 필요가 없는 method를 선언할 때 final을 빼먹는 경우가 많은데, 이 때문에 Java로 작성된 대부분의 프로그램은 method invocation의 overhead가 필요 없이 커지는 경향이 있다. 물론 virtual method를 inlining하는 algorithm도 나와 있으나 모든 경우를 해결하긴 힘들다.
또 다른 이유는 API를 공개할 때 생기는 여파의 차이다. non-virtual method의 경우 해당 method가 어떤 일을 하며 어떤 값을 return하는지 정도만 기술해주면 충분하다. 그러나 virtual method의 경우 API 사용자에 의해 override 될 수 있고 override 된 method가 base class의 method 내에서도 쓰이게 된다. 대부분의 virtual method가 해당 플랫폼이나 API의 hook으로 동작하게 되는데(Template Method가 대표적인 예제) 이 경우 API 작성자는 해당 API가 어떤 경우에 호출되며 base class 안에서 어떤 일을 하는지 또 어떤 invariant를 가져야 하는지 자세하게 명시해야 한다. API 사용자가 이를 제대로 파악하지 못했다면 해당 class는 제대로 동작하지 않을 가능성이 크다.
그리고 virtual method를 default로 선택한 Java의 경우 versioning과 관련된 문제로 새로운 base class를 release하면서 새로운 method를 추가했는데 derived class를 쓰던 사람이 우연히 같은 signature의 method를 정의해서 쓰고 있었다면 이는 원래 의도와 다르게 virtual method가 되면서 override된다. C#의 경우 이런 경우를 막기 위해 virtual method는 반드시 virtual이라 명시하고, derived class에서 이를 override하면 override라는 keyword를 명시해주도록 하고 있다.
Java의 경우 C#의 override와 같은 keyword가 없기 때문에 derived class에서 overriding method를 mis-typing하여도 이를 알아낼 방법이 없다. Java는 새로운 method를 추가되었다고 생각할 뿐이기 때문이다. 또한 base class에서 method name을 바꿀 때도 override란 keyword를 사용한 derived class는 곧바로 compile error가 나겠지만 그렇지 않은 경우 systematic하게 이를 알아낼 방법도 존재하지 않는다.