본문 바로가기
  • 쓸쓸한 개발자의 공부방
C++

[C++] virtual function (가상 함수), function override(오버라이드)

by 심찬 2021. 8. 28.

 

 

주의! 함수 오버라이드가 c++에서 가능하지만 권장하지 않는 코딩이다. 그저 참조용으로만 알아둘 것.

함수 재정의가 필요한 경우에는 무조건 virtual 을 사용해야 한다.

 

 

함수 오버라이드 (function override)

- 기반 클래스가 가진 함수를 파생 클래스가 다시 만드는 것

- 주의! 오바라이딩과 오버로딩(overloading)은 다른 용어

 

#include <iostream>

class Shape
{
public:
    void Draw() { std::cout << "Shape::Draw" << std::endl; }
};

class Rect : public Shape
{
public:
    void Draw() { std::cout << "Rect::Draw" << std::endl; }
};

int main()
{
    Shape s; s.Draw(); // Shape::Draw
    Rect r;  r.Draw(); // Rect::Draw
    
    Shape* p = &r;     //
    p->Draw();         // Shape::Draw
}

기반 클래스 포인터로 파생 클래스를 가리킬 때 override된 함수를 호출하면

C++ 혹은 C#에서는 기반 클래스 함수를 호출한다.

(참고로, java, swift 언어에서는 파생 클래스 함수를 호출함.)

 

함수 바인딩 (binding)

p->Draw() 를 어느 함수와 연결 할 것인가?

 

  방법 1. 컴파일 할 때 결정 하는 방법 - static binding

  방법 2. 실행 할 때 결정 하는 방법 - dynamic binding

 

C++는 기본적으로 컴파일 할 때 함수 호출을 결정한다.

컴파일러는 컴파일 시간에 실제로 p가 어느 객체를 가리키는지 알 수 없다.

컴파일러가 컴파일 시간에 알고 있는 정보는 p는 Shape*라는 사실 밖에 없다.

 


 

Virtual function (가상 함수 )

 

어느 함수를 호출할지는 컴파일 시간에 하지 말고, 실행할 때 결정해 달라는 것.

메모리에 있는 객체를 조사한 후 호출함.

 

일반 멤버 함수와 가상 함수의 차이점

일반 멤버 함수 static binding
컴파일러가 컴파일 시간 호출을 결정
포인터의 타입으로 함수 호출을 결정
Shape::Draw() 호출
가상 함수 (virtual function) dynamic binding
실행 시간에 메모리를 조사해서 함수 호출을 결정
실제 메모리에 놓인 객체 타입으로 함수 호출 결정
Rect::Draw() 호출

 

Draw()를 virtual로 정의하면 실행 시간에 정의된 Rect 객체로 판단해서 Rect의 Draw()를 호출한다.

파생 클래스에 재정의 할거라면 virtual로 정의하는게 원칙!

#include <iostream>

class Shape
{
public:
    virtual void Draw() { std::cout << "Shape::Draw" << std::endl; }
};
class Rect : public Shape
{
public:
    virtual void Draw() { std::cout << "Rect::Draw" << std::endl; }
};

int main()
{
    Shape s; 
    Rect r;  
    
    Shape* p = &r;
    
    //--------------
    //int n = 0;
    //std::cin >> n;
    //if ( n == 1 ) p = &s;
    //--------------
    
    // 아래 코드를 컴파일 할때
    // p가 어느객체를 가리킬지 컴파일러가 알수 있을까 ?
    
    p->Draw();    // Rect::Draw
}

 

C++ 에서 파생 클래스에서 재정의 할 함수에 대해서는 무조건 virtual을 쓰자! 

 

가상 함수가 아닌 함수를 재정의 하지 말라.

C++의 격언이라고 하네요.

 

 

댓글