![[C++] 다형성과 가상 소멸자](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWB2bS%2FbtsMUrxouUA%2F6Lqw6AbYE9q31kYQ6JsTy1%2Fimg.png)
C++은 객체 지향 프로그래밍 언어이다.
OOP의 속성으로는 은닉화, 캡슐화, 상속성, 다형성이 있고 OOP의 특성으로는 추상화가 있다.
이중에서도 다형성은 쉽게 말하면 '모습은 같은데 형태는 다른 것'을 의미한다.
상속관계에서 다형성이 활용되는데 주의해야할 것들 중 이번 글은 '가상 소멸자'에 대한 부분이다.
parent* p = new child();
우리는 위처럼 '업캐스팅'을 자주 사용할 때가 많다.
위 코드를 컴퓨터 입장에서 보면 부모 클래스 포인터로 무엇인가 가르키고 있기 때문에 가르키는 대상이 무조건 부모 클래스 객체라고 생각할 수 밖에 없다.
(원하는 동작은 parent*로 가르키고 있지만 실 객체는 child라고 인식 시키고 싶은 것이다)
위 코드는 child클래스가 parent클래스로 부터 함수를 오버라이딩하게되면 문제가 발생한다.
parent 클래스에 func라는 함수가 있고 child클래스가 이를 오버라이딩 하여 똑같이 func라는 함수가 존재하게 되면
아래 코드에서 원하는 동작은 child클래스의 func함수가 호출되기를 원하지만 '정적 바인딩'으로 인해 parent클래스의 func함수가 호출되게 된다.
parent* p = new child();
p->func(); // parent 클래스의 func() 호출
정적으로 함수가 바인딩되어 컴파일 타임에 어떤 함수가 호출될지가 결정되어 있다.
더큰 문제는 객체가 소멸하는 시점인데 객체의 생성 시점은 '부모->자식' 순이지만 객체 소멸 과정은 '자식->부모'이다.
parent* p = new child();
delete p;
delete는 해당 객체의 소멸자를 호출하고 메모리를 해제하는 키워드이다. 이때 소멸자도 정적으로 바인딩 되어 있기 때문에 부모의 소멸자만 호출하게 되고 자식의 소멸자는 호출하지 않게 된다. 이렇게 되면 메모리 누수가 발생할 확률이 높다.
그럼 위 문제를 컴파일 타임에 정적(고정)으로 바인딩을 하지 않고 그때그때 실제 객체가 무엇인지 확인 한뒤 호출하게 한다면 해결할 수 있을 것이다.
C++에서는 런타임에 실제 객체가 어떤 타입인지 확인하여 실제 객체에 해당하는 함수를 호출할 수 있게 해주는 키워드가 있다.
부모 클래스의 멤버 함수 앞에 'virtual'키워드를 붙여주면 해당 함수는 '가상 함수'가 되고 이를 오버 라이딩 하게되면 '가상함수 오버라이딩'을 하게 되는 것이다.
class parent
{
virtual func() {}
}
class child
{
virtual func() {} override;
}
이렇게 가상 함수를 오버라이딩한 객체를 생성하게 되면 객체의 앞부분 주소에는 가상함수 테이블을 가르키는 vptr이 존재하게 되고 vptr을 통해 가상 함수 테이블을 참조하여 런타임에 실제 객체의 함수를 호출을 하여 문제를 해결할 수 있다.
정리하자면 상속을 받는 경우 소멸자에 무조건 virtual키워드를 붙여주도록하자.
'CPP' 카테고리의 다른 글
Stomp Allocator (0) | 2025.04.04 |
---|---|
[C++] 스마트 포인터 (0) | 2023.09.14 |
[C++] union (DX Matrix) (0) | 2023.09.04 |
[C++] initializer_list (0) | 2023.08.23 |
[C++] 가변 길이 템플릿과 후행 리턴 타입 (0) | 2023.08.20 |
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!