[완료]virtual 소멸자에 대한 질문
글쓴이: bluekyu / 작성시간: 수, 2011/02/09 - 7:44오후
virtual 소멸자에 대해서 질문이 있는데, 포럼이나 다른 곳에서 원하는 답변을 얻지 못해서 질문 올려봅니다.
class A{ char a; public: A(){a = new char[10];} ~A(){delete []a;} }; class B: A{ char b; public: B(){b = new char[10];} ~B(){delete []b;} }; int main(){ A* x = new B; delete x; return 0; }
위와 같이 일반적으로 기반 클래스인 A가 파생 클래스 B 객체를 참조하고 있으면 ~A()에 virtual을 써주어야 ~B()가 실행된다는 것은 알고 있습니다.
그런데 제가 공부하고 있는 책에 있는 문제를 코딩하다 보니까 파생 클래스에서 아래처럼 소멸자가 필요 없는 경우가 생겼습니다.
class A{ char a; public: A(){a = new char[10];} ~A(){delete []a;} }; class B: A{ // B 클래스 자체로는 소멸자를 따로 생성할 필요가 없음 ... public: B(){...} }; int main(){ A* x = new B; delete x; return 0; }
그런데 소멸자와 관련에서 C++ 프로그래밍 언어 책을 찾아본 적이 있는데, x가 가리키고 있는 객체의 타입은 정확히 무엇인지 모르므로 virtual을 선언하여 x가 가리키고 있는 객체를 완벽하게 소멸시킬 수 있다고 되어 있었습니다.
그렇기 때문에 맨 위와 같은 코드에서는 virtual 선언이 되어 있지 않으면 A 클래스의 소멸자만 실행되는 것으로 알고 있었습니다.
따라서 바로 위와 같은 코드(소멸자가 필요 없는 경우)에서도 기반 클래스인 A의 소멸자에 virtual이 반드시 들어가야 한다고 생각을 하는데, 책에서는 그렇게 되어 있지 않습니다.
그래서 궁금증이 생겼는데, 바로 위와 같은 코드에서는 virtual 선언이 필요가 없나요? 그리고 제가 생각하고 있는 것이 잘못 되었나요?
Forums:
필요 없습니다. 부모클래스의 가상함수는,
필요 없습니다.
부모클래스의 가상함수는, 자식클래스에서 virtual 키워드를 쓰던 안쓰던, 오버라이딩을 하던 안하던 자동으로 가상함수가 됩니다.
소멸자도 마찬가지입니다.
따라서 생각하고 계신것은 잘못되었습니다.
명시적으로 쓰는게 좋다 나쁘다의 문제는 남을수 있겠지만요.
필요합니다...
위의 클래스 정의로 아래 코드를 실행하면, 클래스 B의 객체가 소멸되더라도 기반(=베이스) 클래스인 A의 소멸자만 호출하게 됩니다.
따라서 클래스 B의 생성자에서 메모리 할당한 b의 메모리도 제거되어야 합니다. 기반 클래스인 A의 소멸자에 가상화가 이뤄지지 않으면 메모리 leak이 발생합니다.
그러나 아래 처럼 하면, delete로 객체를 소멸시키면 객체 B의 소멸자, 그리고 객체 A의 소멸자가 호출되게 됩니다.
참고로 아래처럼 여러번 상속한 클래스 C 객체를 생성하였다가 소멸시켜도 ~C(), ~B(), ~A() 순서로 소멸자가 호출됩니다.
즉, 기반 클래스에서 한번만 가상함수로 선언하면 됩니다. (자동으로 상속됨)
모두들 행복하세요~
질문의 의도가 잘못 전달 되었네요 ;;
괜히 코드를 축약해서 표현했나봅니다.
질문의 요지는 위 코드에서 클래스 A의 소멸자에 virtual의 선언을 해주어야 하느냐 입니다.
제 생각은 A 클래스에 virtual 선언을 하지 않게 되면 B 객체의 소멸자가 호출되지 못해서 B 객체 부분의 메모리가 해제 되지 못한다고 생각합니다.
(즉, 질문에 써 있듯이 x가 가리키고 있는 객체의 정확한 타입을 알지 못하기 때문에 객체 A 부분의 메모리만 해제하고, 클래스 B의 소멸자를 호출하지 못해서 객체 B 부분의 메모리를 해제하지 못한다고 생각하는 것입니다.)
/*** Signature ******************
* blog: http://blog.bluekyu.me/ *
********************************/
..
뭐, 스펙과 교과서 그대로이지만, 이 예제를 실행해보시면 도움되겠네요.
아래에서 ~A 앞에 virtual 주고, 결과를 보고, 빼고 결과를 보세요. 원하시는 결과와 의도를 눈으로 확인하실수 있을 꺼에요.
"B의 destructor 가 영원히 변하지 않는다"면, 추가하실 필요 없을 듯 합니다. 하지만 B* x = new B(); 이런식으로 쓰면 답없죠.
부모클래스의 소멸자는 virtual로 해주어야합니다.
부모클래스의 소멸자는 virtual로 해주어야합니다.
이유는 말씀하신대로입니다.
해제해야할 자원이 없으므로
B 클래스에는 해제해야할 자원(포인터)이 없으니 굳이 기반 클래스의 소멸자를 가상으로 선언할 필요는 없을 것으로 보입니다.
.
답글 모두 감사합니다.
/*** Signature ******************
* blog: http://blog.bluekyu.me/ *
********************************/
저두 덕분에 공부에 큰 도움을 받았습니다.
저두 덕분에 공부에 큰 도움을 받았습니다.
질문 하신 분도, 답을 해주신 모든 분들 복받으실거에요.
댓글 달기