열렬히.뛰기

virtual와 가상함수

Language > 프로그래밍 언어 > C++ > Cpp : 기초 > virtual와 가상함수

가상함수

가상함수 만들기

멤버함수의 맨 앞에 virtual을 붙이면 그 멤버함수는 가상함수가 됨.

가상함수는 자식 클래스에서 반드시 구현을 해줘야 함. (안 그러면 컴파일이 안됨)

cpp
#include <iostream>
using namespace std;

class Base {
    virtual void show() { cout << "Base::Show" << std::endl; }
};

class Derived : public Base {
    void show() override { cout << "Derived::show" << endl;}
};

int main() {
		Base* basePtr = new Derived();
		basePtr->show();  // Derived 클래스의 show 함수가 호출됨
		delete basePtr;
		return 0;
}

순수 가상함수

아무것도 적히지 않은(=구현부가 없는) 가상함수

  • 부모 클래스에서는 구현부가 없고, 자식 클래스에 구현부가 존재.

  • cpp에 존재하지 않는 인터페이스를 순수 가상함수로 구현할 수 있음.

    (클래스 전체를 순수 가상함수로 채우면 됨.)

cpp
Class Base
{
	public :
		virtual void somefun() = 0;
};

가상함수의 특징

런타임 다형성

  • 가상 함수는 런타임 시에 객체의 실제 타입을 기반으로 호출

    이는 포인터나 참조를 통해 객체에 접근할 때 유용하게 사용.

  • 예를 들어, 부모 클래스의 포인터를 통해 자식 클래스의 가상 함수를 호출할 수 있음.

cpp
using namespace std;

class Base {
    virtual void foo() { cout << "Base::foo()" << endl;}
};

class Derived : public Base {
    void foo() override { cout << "Derived::foo()" << endl; }
};

int main() {
    Base* obj = new Derived();
    obj->foo();  // Derived::foo() 가 호출됨
    delete obj; 
		return 0;
}

동적 바인딩

  • 함수가 어떤 코드를 통해 실행될 지를 프로그램이 실행될 때 결정하는 것.
  • 일반적인 함수는 정적 바인딩이 이뤄진다. 함수가 어떤 코드를 통해 실행될 지를 프로그램이 개발될 때 결정하게 된다는 뜻.
  • 이 과정에서 가상함수 테이블(vTable)을 사용

가상함수 테이블

  • 영어로는 virtual function table, 줄여서 vTable 이라고 함.
  • 가상함수를 하나라도 가진 클래스라면, 해당 클래스가 객체화될 때마다 무조건 하나의 가상함수 테이블이 생성됨.
cpp
부모 클래스 AAA
key                    value
------------------------------
void AAA::func1()  --> 0x1024
void AAA::func2()  --> 0x2048


자식 클래스 BBB
key                    value
------------------------------
void BBB::func1()  --> 0x3084
void AAA::func2()  --> 0x2048
void BBB::func1()  --> 0x4096
  • BBB클래스의 가상함수 테이블을 살펴보면, 오버라이딩 된 AAA클래스의 func1 함수에 대한 정보가 없다.
  • 그래서 BBB클래스의 Func1함수가 대신 호출되는데, 이것이 바로 가상함수의 호출원리이다.
cpp
< 가상 소멸자 >
* 기반클래스의 포인터가 파생클래스의 동적 객체를 가리키고, 
그 포인터를 통해 동적 객체를 제거했을 때 파생클래스의 소멸자까지 
호출되도록 하려면…?

기반 클래스의 소멸자를 다음과 같이 
가상 소멸자(Virtual Destructor)로 만들어야 함.

가상함수의 장/단점 정리

cpp
<장점>
- 실행 시 다형성이라는 융통성을 갖게 됨
- 생성조건 및 상황에 따라 코드 변경.

<단점>
- 가상함수 테이블 때문에 일반적인 클래스보다 공간을 좀 더 차지
- 가상함수 테이블 때문에 조금 더 호출 시간이 길어진다.