Java와 달리 C #은 기본적으로 메서드를 비가 상 함수로 취급하는 이유는 무엇입니까? 다른 가능한 결과보다 성능 문제 일 가능성이 더 높습니까?
Anders Hejlsberg의 한 단락을 읽고 기존 아키텍처가 가져다주는 몇 가지 이점에 대해 생각했습니다. 그러나 부작용은 어떻습니까? 기본적으로 가상이 아닌 방법을 사용하는 것이 정말 좋은 절충안입니까?
답변
상속을 이용할 수 있도록 클래스를 설계 해야 합니다. virtual
기본적으로 메서드 가 있다는 것은 클래스의 모든 함수를 플러그 아웃하고 다른 함수로 대체 할 수 있음을 의미합니다. 이는 실제로 좋지 않습니다. 많은 사람들은 수업이 sealed
기본적으로 이루어져야한다고 생각합니다 .
virtual
메서드는 성능에 약간의 영향을 미칠 수도 있습니다. 그러나 이것이 주된 이유는 아닐 것입니다.
답변
기본적으로 비가 상이 아닌 것이 작업을 수행하는 올바른 방법이라는 합의가 여기에있는 것 같습니다. 나는 다른 쪽에서 내려갈 것입니다. – 저는 실용적이라고 생각합니다 – 울타리의 측면.
대부분의 정당화는 “우리가 당신에게 힘을 주면 당신이 스스로를 해칠 수있다”는 주장처럼 나에게 읽혀진다. 프로그래머로부터?!
상속 및 / 또는 확장 성을 위해 라이브러리를 설계하기에 충분하지 않은 (또는 충분한 시간이있는) 코더가 내가 수정하거나 조정해야 할 라이브러리를 정확히 생성 한 코더 인 것처럼 보입니다. 재정의 기능이 가장 유용하게 사용되는 라이브러리.
추악하고 절박한 해결 방법 코드를 작성해야하는 횟수 (또는 사용을 포기하고 대체 솔루션을 롤링하기 위해)해야하는 횟수는 내가 물린 횟수보다 훨씬 더 큽니다. 예를 들어 Java에서) 디자이너가 내가 생각하지 않았을 수도있는 곳을 재정의함으로써.
기본적으로 가상이 아닌 것은 내 삶을 더 어렵게 만듭니다.
업데이트 : 내가 실제로 질문에 대답하지 않았다는 것이 [정확히] 지적되었습니다. 그래서-그리고 다소 늦게 된 것에 대해 사과합니다 ….
저는 “C #은 프로그래머보다 프로그램을 더 중요시하는 잘못된 결정을 내렸기 때문에 기본적으로 비가 상 메서드를 구현하는 C #”과 같은 간결한 것을 작성할 수 있기를 원했습니다. (성능 (조기 최적화, 누구?) 또는 클래스 동작 보장과 같은이 질문에 대한 다른 답변을 기반으로 어느 정도 정당화 될 수 있다고 생각합니다.)
그러나 나는 Stack Overflow가 원하는 결정적인 대답이 아니라 내 의견을 말하고 있다는 것을 알고 있습니다. 확실히, 최고 수준에서 결정적인 (그러나 도움이되지 않는) 대답은 다음과 같다고 생각했습니다.
언어 설계자가 결정을 내렸고 그것이 그들이 선택한 것이기 때문에 기본적으로 가상이 아닙니다.
이제 나는 그들이 그 결정을 내린 정확한 이유를 우리는 결코 …. 아, 기다려! 대화의 대본!
따라서 API 재정의의 위험성과 상속을 위해 명시 적으로 설계해야하는 필요성에 대한 답변과 의견이 올바른 방향으로 진행되고 있지만 중요한 시간적 측면이 누락 된 것 같습니다. Anders의 주요 관심사는 클래스 또는 API의 암시 적 유지에 대한 것이 었습니다. 버전 간 계약 . 그리고 그는 실제로 플랫폼 위에서 사용자 코드 변경에 대해 걱정하기보다는 .Net / C # 플랫폼이 코드 아래에서 변경되도록 허용하는 것에 대해 더 걱정한다고 생각합니다. (그리고 그의 “실용적인”관점은 그가 다른 쪽에서 바라보고 있기 때문에 나의 것과 정반대입니다.)
(그러나 그들은 기본적으로 가상을 선택하고 코드베이스를 통해 “최종”을 뽑아 낼 수 없었습니까? 아마도 그것은 똑같지 않을 것입니다 .. Anders는 분명히 저보다 똑똑하기 때문에 거짓말을하겠습니다.)
답변
메서드가 재정의되고이를위한 디자인이 아니라는 사실을 잊기 쉽기 때문입니다. C #은 가상으로 만들기 전에 생각하게합니다. 이것은 훌륭한 디자인 결정이라고 생각합니다. 일부 사람들 (예 : Jon Skeet)은 클래스가 기본적으로 봉인되어야한다고 말했습니다.
답변
다른 사람들의 말을 요약하면 몇 가지 이유가 있습니다.
1- C #에는 C ++에서 직접 나오는 구문 및 의미 체계가 많이 있습니다. C ++에서 기본적으로 가상이 아닌 메서드가 C #에 영향을 미쳤다는 사실.
2- 모든 메서드 호출은 개체의 가상 테이블을 사용해야하므로 기본적으로 모든 메서드를 가상으로 설정하는 것은 성능 문제입니다. 또한 이는 메서드를 인라인하고 다른 종류의 최적화를 수행하는 Just-In-Time 컴파일러의 기능을 강력하게 제한합니다.
3- 가장 중요한 것은 메서드가 기본적으로 가상이 아닌 경우 클래스의 동작을 보장 할 수 있다는 것입니다. Java와 같이 기본적으로 가상 인 경우 간단한 getter 메서드가 의도 한대로 수행된다는 것을 보장 할 수 없습니다. 방법 및 / 또는 클래스 최종).
Zifre가 언급했듯이 C # 언어가 한 단계 더 나아가 기본적으로 클래스를 봉인하지 않은 이유가 궁금 할 수 있습니다. 이것은 구현 상속 문제에 대한 전체 토론의 일부이며 매우 흥미로운 주제입니다.
답변
C #은 C ++의 영향을받습니다. C ++는 기본적으로 동적 디스패치 (가상 함수)를 활성화하지 않습니다. 이에 대한 한 가지 (좋은?) 주장은 “클래스 계층의 구성원 인 클래스를 얼마나 자주 구현합니까?”라는 질문입니다. 기본적으로 동적 디스패치를 사용하지 않는 또 다른 이유는 메모리 공간입니다. 가상 테이블을 가리키는 가상 포인터 (vpointer)가없는 클래스 는 물론 후기 바인딩이 활성화 된 해당 클래스보다 작습니다.
성능 문제는 “예”또는 “아니오”라고 말하기가 쉽지 않습니다. 그 이유는 C #의 런타임 최적화 인 JIT (Just In Time) 컴파일 때문입니다.
” 가상 통화 속도 .. “에 대한 또 다른 유사한 질문
답변
단순한 이유는 성능 비용 외에도 설계 및 유지 보수 비용입니다. 가상 메서드는 비가 상 메서드에 비해 추가 비용이 발생합니다. 클래스 디자이너는 메서드가 다른 클래스에 의해 재정의 될 때 발생하는 작업을 계획해야하기 때문입니다. 특정 메서드가 내부 상태를 업데이트하거나 특정 동작이있을 것으로 예상하는 경우 이는 큰 영향을 미칩니다. 이제 파생 클래스가 해당 동작을 변경할 때 어떤 일이 발생하는지 계획해야합니다. 그런 상황에서 신뢰할 수있는 코드를 작성하는 것이 훨씬 더 어렵습니다.
비가 상 방법을 사용하면 완벽하게 제어 할 수 있습니다. 잘못되는 것은 원저자의 잘못입니다. 코드는 추론하기가 훨씬 쉽습니다.
답변
모든 C # 메서드가 가상이면 vtbl이 훨씬 더 커집니다.
C # 개체에는 클래스에 가상 메서드가 정의되어있는 경우에만 가상 메서드가 있습니다. 모든 개체에 vtbl에 해당하는 형식 정보가 포함되어 있지만 가상 메서드가 정의되지 않은 경우 기본 개체 메서드 만 존재합니다.
@Tom Hawtin : C ++, C # 및 Java가 모두 C 언어 계열이라고 말하는 것이 더 정확할 것입니다. 🙂