Skip to content

Latest commit

 

History

History
58 lines (49 loc) · 3.35 KB

PrincipleOfVirtualFunctionInCpp.md

File metadata and controls

58 lines (49 loc) · 3.35 KB

가상함수의 동작 원리

작성자

tdm1223 Stupid07

C++에서 멤버함수

  • C++에서 객체가 생성되면 멤버 변수는 객체 내에 존재한다.
  • 멤버 함수는 메모리의 한 공간에 별도로 위치하고 이 함수가 정의된 클래스의 모든 객체가 이를 공유하는 형태를 취한다.

C++에서 가상함수

  • 한 개 이상의 가상 함수를 포함하는 클래스에 대해서는 컴파일러가상 함수 테이블을 만든다.
  • 가상 함수 테이블은 실제 호출되어야 할 함수의 위치정보를 담고 있는 테이블이다.
  • 가상 함수 테이블은 객체의 생성과 상관없이 main 함수가 호출되기 이전에 메모리 공간에 할당된다.
  • 가상 함수 테이블은 멤버 함수의 호출에 사용되는 일종의 데이터이다.
  • 따라서 가상 함수를 포함하는 클래스는 가상 함수 테이블을 이용해 함수를 호출하므로 포인터가 가리키는 클래스의 멤버함수가 아닌 객체 선언시 자신의 클래스에 맞게 오버라이딩된 함수를 호출한다.

가상함수의 동작 원리를 알수 있는 예제

class A
{
public:
    void Func() { cout << "A func" << endl; }
    virtual void Show() { cout << "A show" << endl; }
};

class B : public A
{
public:
    void Func() { cout << "B func" << endl; }
    void Show() { cout << "B show" << endl; }
};

int main()
{
    A* a = new A();
    A* b = new B();
    a->Func(); // 결과는 A func
    b->Func(); // 결과는 A func(포인터 b는 A 클래스이고, 가상함수가 아니므로 포인터가 가리키는 A 클래스에 바인딩된 함수를 호출한다)
    a->Show(); // 결과는 A show
    b->Show(); // 결과는 B show(포인터 b는 A 클래스이지만, 가상함수이므로 함수 테이블에 오버라이딩된 B 클래스의 함수를 호출한다)
    
    return 0;
}
  • Func 함수는 멤버 함수의 동작을 보여주기 위해 추가하였다.
  • 멤버 함수의 경우 가상 함수와 다르게 포인터가 가리키는 클래스에 바인딩된 함수만을 호출하게 된다.
  • 위 구조에서 B 클래스가상 함수 테이블을 살펴보면, 오버 라이딩된 A클래스의 Show 함수에 대한 정보가 없다.
  • 가상 함수의 호출 원리로 b의 Show함수를 호출하면 B클래스의 Show함수가 호출된다.

그렇다면 실제 현업에서 가상 함수를 많이 이용하는가?

  • 일하는 곳마다 다르겠지만 개인적으론 가상 함수를 많이 쓰지 않을 것이라고 생각한다.
  • 첫 번째로 가상 함수를 쓰게되면 내부적으로 가상 함수 테이블을 생성해서 메모리에 유지하게 되므로 성능에 문제가 있다.
  • 두 번째로 프로젝트에서 상속 관계가 복잡해지면 가상 함수로 인해 동적으로 함수를 호출할 경우
  • 포인터를 통해 내가 원하는 함수가 반드시 호출 될 것을 보장하기 어려워지고 어떤 함수가 호출되는지 추적하기 힘들다.
  • 결국 클래스에따라 정적으로 바인딩된 함수를 호출하는것이 더 명시적이고 개발이 편리할 것 같다.