본문 바로가기
언어(C, C++, C#)

[C#] 가상 함수 테이블

by 적용1 2024. 11. 17.
728x90

가상 함수란?

  • 기본 클래스에서 선언되고, 파생 클래스에서 재정의(override)할 수 있는 함수이다.
  • virtual 키워드를 통해 선언하고, override 키워드를 통해 재정의할 수 있다.

overriding, overloading

  • overloading(오버로딩) : 같은 이름의 메서드를 여러 개 정의하는 기법으로, 메서드의 매개변수의 수나 타입을 다르게 설정하여 동일한 메서드 이름을 여러 용도로 사용할 수 있게 해준다.

  • overriding(오버라이딩) : 부모 클래스에서 정의된 메서드를 자식 클래스에서 재정의하여 사용하는 기법이다.

    런타임 다형성을 구현하는 중요한 방법 중의 하나로, 자식 클래스에서 부모 클래스의 메서드를 변경하여 자식 클래스만의 방식으로 동작하게 할 수 있다.

Virtual Table(VTable)

  • 한 클래스가 해당 클래스나 상위 클래스에서 하나 이상의 가상 메서드(virtual, abstract)를 가진다면, 해당 클래스의 Method Table 메타데이터 내에 Virtual Table을 가지게 된다.

    Virtual Table은 기본적으로 메서드 포인터를 저장하는 배열이다. 쉽게 말해, 각 가상 메서드에 대한 함수 포인터 목록이다.

  • VTable은 객체가 가리키는 heap 메모리에 존재하는 Type Handle이 가리키는 곳의 Method Table 내에 위치한다.

    Type Handle은 heap 메모리 안의 객체의 헤더에 포함되어 있다.
    출처 : https://velog.io/@yejun283/2024.01.05
  • 파생 클래스의 경우, 부모 클래스의 Method Table 및 VTable을 바탕으로 자신의 Method Table을 만들어 가리키게 된다.

    이 때, 재정의하지 않은 메서드에 대해서는 같은 내용(메서드 주소)을 담은 table entry를 가리키게 되는데, 재정의하게 된다면 자신만의 VTable에서 다른 내용이 채워지게 된다.

  • 만약 Base 클래스가 가상 메서드를 가지지 않는다면 파생 클래스는 Base 클래스의 메서드를 VTable에 슬롯을 추가하지 않는다.

  • C# / .NET 에서 모든 클래스(또는 구조체)는 System.Object 클래스를 상속받으므로 Virtual Table을 갖는다.

    모든 클래스는 System.Object 클래스의 3개의 가상 메서드(ToString(), Equals(), GetHashCode())를 자신의 VTable 안에 가지게 된다.

  • 하나의 클래스로 여러 객체를 만들어도, 해당 객체들은 같은 메소드 테이블을 가리키게 된다.

Hiding

  • 파생 클래스에서 override를 사용하지 않고 동일한 메서드 명을 사용한 경우를 Hiding이라 한다.
class A
{
    public virtual void Run1()
    {
        Console.WriteLine("A.Run1");
    }
    public virtual void Run2() 
    {
        Console.WriteLine("A.Run2");
    }
}
class B : A
{
    public override void Run1()
    {
        Console.WriteLine("B.Run1");
    }
    public new void Run2()
    {
        Console.WriteLine("B.Run2");
    }
}

class Program
{
    static void Main(string[] args)
    {
        //케이스-A
        A a = new B();        
        a.Run2();  // 베이스의 Run2 실행

        //케이스-B
        B b = (B) a;
        b.Run2(); // 파생클래스 Run2 실행
    }
}

 

  • 위 코드의 경우, 클래스 B의 Run2를 정의할 때 new 키워드를 사용하게 되는데, 이 키워드는 해당 메서드가 Base 클래스의 이름이 같은 메서드와 관련이 없다는 것을 의미한다.

    new 키워드를 사용하지 않으면 Warning이 뜨지만 실제 런타임에서는 new를 사용했을 때와 동일하게 실행된다.

  • Hiding의 경우 객체지향 프로그래밍의 다형성을 활요하지 않기 때문에 특수한 경우가 아니면 사용되지 않는다.

 

 

Reference : https://velog.io/@yejun283/2024.01.05

728x90