C#의 클래스는 왜 virtual 하지 않은가?

라는 궁금증을 꽤 오래전부터 가지고 있었습니다.

아시다시피, Java 클래스의 멤버는 기본적으로 virtual 합니다.

즉, 클래스 작성자의 의도와 상관없이, 다른 사람이 파생을 통해 임의로 구현을 달리할 수 있습니다.
다형성의 결정권이 파생 클래스에게 있는 것이죠.

그런데, C#에서는 클래스 작성자가 virtual 로 한정하지 한 파생 클래스 작성자가 임의로 구현을 달리할 수는 없습니다. 즉, 다형성의 결정권이 기반 클래스에게 있다고 할 수 있습니다.

C#은 자바를 모티브로 만들어졌지만, 다형성 실현 방식에 관해서는 자바와 반대되는 입장을 취하고 있는 것이죠.

방식이 다르다는 점은 알겠는데, "도대체 어떤 이득이 있길래"라는 해소되지 않은 궁금증이 있었습니다. 그런데, 최근에 조금이나마 그 이득을 짐작하게 되었습니다.

class Old
{
    public string Price => "10,000 원";
}

// 다형성을 파생이 결정한다면,
class New : Old
{
    public override string Price => "10,000 원입니다.";
}

New 가 나오기 전 Old의 클라이언트들은 아래와 같이 사용했을 수도 있습니다.

string priceText = old.Price + "입니다."

Old.Price는 “10,000 원” 까지만 출력한다는 기대를 바탕으로 클라이언트 코드가 작성된 것이죠.
그런데, 다형성이 발동한 경우, 이 기대에 배신을 당합니다.

// "10,000 원입니다.입니다."

.

C#이 처음 소개되었을 시기에는, Java 를 통해 객체 지향의 개념이 이제 막 퍼지기 시작했을 시기였을 것입니다.

클래스 사용자는 클래스의 정의를 믿고, 파생자는 다형성 장치를 수시로 사용했겠죠.

그런데, 부분적으로는 참인 위 두 개의 명제가 합쳐지면 거짓이 되는 역설적인 상황을 Java 사용자들은 심심치 않게 마주쳤을 것으로 추측이 됩니다.

C#은 이러한 역설을 방지하기 위해, 클래스 사용자에게 다형성으로 인한 변동 가능성을 미리 고지하는 방식을 선택한 것은 아닌가 하는 짐작을 했습니다.

제품의 사용 설명서에서 가끔 보이는 "변경 고지문"과 같은 역할을 할 수 있도록 말이죠.

“색상, 디자인 등은 제품의 성능 향상을 위해 예고 없이 변경될 수 있습니다”

.

이 장치로 인해, 클래스 사용자는 class의 멤버 중 무한 신뢰해도 되는 것들과,

string GetString() ...

마냥 신뢰할 수 만은 없는 것들을 구분할 수 있게 된 것이죠.

virtual string GetString()
10 Likes

@BigSquare 좋은 글 감사합니다!!

object 클래스의 ToString(), Equals()이 떠오르네요!

C# 클래스는 virtual abstract override 같은 키워드를 통해 클래스 계층간에 유연하고 명확한 설계를 할 수 있어서 참 좋은 것 같습니다. 어떤 객체를 오버라이드 하거나 확장할지 재미있게 관리할 수 있죠.

(저는 자바는 잘 몰라유! ㅠ:rofl:)

2 Likes

저도 자바 잠깐 만져봤을 뿐이지만, C#과 거의 동일합니다.
키워드 측면에서 C#이 약간 좀 더 다듬어졌다고 볼 수 있습니다.

파생 키워드
Java : “extends”
C# : " : "

구현 키워드
Java : “implements”
C# : " : "

2 Likes