지식
[C++] virtual 탐구
라구넹
2025. 5. 27. 14:10
class Base {
public:
void sayHello() { std::cout << "Hello from Base\n"; }
virtual void greet() { std::cout << "Greet from Base\n"; }
};
class Derived : public Base {
public:
void sayHello() { std::cout << "Hello from Derived\n"; }
void greet() override { std::cout << "Greet from Derived\n"; }
};
int main() {
Base* ptr = new Derived;
ptr->sayHello(); // Base::sayHello()
ptr->greet(); // Derived::greet() ← virtual 덕분에 동적 바인딩
}
sayHello -> 정적 바인딩 => 컴파일 타임에 결정
greet -> 런타임에 동적으로 호출
가상 함수 테이블 (vtable)
- 클래스에 하나라도 virtual 있음 => vtable 생성
- 객체는 해당 클래스의 vptr(가상 테이블 포인터) 소유
- 가상 함수 호출: vptr을 따라간 뒤 vtable에서 함수 포인터를 통해 호출
* 추가적인 포인터 참조이기에 성능 오버헤드는 있음
override와 final
override: 안써도 작동은 하는데, 오타 방지 등을 위해 권장 사항
final: 더 이상 오버라이드 불가
소멸자와 virtual
기본 클래스의 소멸자는 반드시 virtual로 선언해야 함
이렇게 안하면 파생 클래스의 소멸자가 호출되지 않아 리소스 누수 발생 위험
순수 가상 함수와 추상 클래스
class Abstract {
public:
virtual void run() = 0; // 순수 가상 함수
};
인스턴스화 불가, 반드시 파생 클래스에서 구현 필요
virtual vs non-virtual
항목 | virtual | non-virtual |
바인딩 시점 | 런타임 | 컴파일 타임 |
오버헤드 | vtable 참조 | 없음 |
인라인화 | 어려움 | 가능 |
유연성 | 높음 | 낮음 |
다중 상속에서의 가상 함수
class A {
public:
virtual void f();
};
class B {
public:
virtual void g();
};
class C : public A, public B {
public:
void f() override;
void g() override;
};
C -> 두 개의 vptr,, 각각 A, B의 vtable을 관리
virtual | 런타임 다형성을 구현하는 키워드 |
override | 오버라이딩 의도를 명확히 함 |
final | 더 이상 오버라이딩 금지 |
vtable | 클래스별 가상 함수 목록 |
vptr | 객체가 vtable을 가리키는 포인터 |
가상 소멸자 | 상속 구조에서 필수 |
성능 | 약간의 오버헤드 존재 |