생성자/소멸자가 호출되지 않습니다.

hyunya77의 이미지

#include <stdio.h>
 
class Transport
{
public:
	virtual void transportFunc() = 0;
};
 
 
class MyTransport : public Transport
{
public:
	MyTransport();
	virtual ~MyTransport();
 
	virtual void transportFunc();
};
 
MyTransport::MyTransport()
{
	printf("%s\n", __func__);
}
 
MyTransport::~MyTransport()
{
	printf("%s\n", __func__);
}
 
 
void MyTransport::transportFunc()
{
	printf("MyTransport::%s\n", __func__);
}
 
class Test
{
public:
	Test();
	virtual ~Test();
	Transport *m_trans;
 
	void testFunc();
};
 
Test::Test()
{
	printf("%s\n", __func__);
}
 
Test::~Test()
{
	printf("%s\n", __func__);
}
 
void Test::testFunc()
{
	printf("%s\n", __func__);
 
	m_trans = new MyTransport();
	m_trans->transportFunc();
	delete m_trans;
}
 
 
int main() {
	Test test;
	test.testFunc();
 
	return 0;
}

위와 같은 코드입니다만,
MyTransport() 와 ~MyTransport()가 호출되지 않고있습니다.
m_trans 변수가 Transport 부모 class type이니 (정의되어 있지는 않지만) Transport(), ~Transport()가 대신
호출되고 있는 것이라 짐작하고 있습니다.

하지만 여기까지는 짐작이 가는데, "delete m_trans"시에 MyTransport() 와 ~MyTransport()가 호출되었으면 합니다.
그런데 어떻게 수정하면 될지 잘 모르겠네요. 상속구조자체는 그대로 두고 상속받은 클래서의 생성/소멸자가
호출되게 하려면 어떻게 해야하나요?

hyunya77의 이미지

#include <stdio.h>
 
class Transport
{
public:
	Transport() { printf("%s\n", __func__); };
	virtual ~Transport() { printf("%s\n", __func__); };
	virtual void transportFunc() = 0;
};
 
 
class MyTransport : public Transport
{
public:
	MyTransport();
	virtual ~MyTransport();
 
	virtual void transportFunc();
};
 
MyTransport::MyTransport()
{
	printf("%s\n", __func__);
}
 
MyTransport::~MyTransport()
{
	printf("%s\n", __func__);
}
 
 
void MyTransport::transportFunc()
{
	printf("MyTransport::%s\n", __func__);
}
 
class Test
{
public:
	Test();
	virtual ~Test();
	Transport *m_trans;
 
	void testFunc();
};
 
Test::Test()
{
	printf("%s\n", __func__);
}
 
Test::~Test()
{
	printf("%s\n", __func__);
}
 
void Test::testFunc()
{
	printf("%s\n", __func__);
 
	m_trans = new MyTransport();
	m_trans->transportFunc();
	delete m_trans;
}
 
 
int main() {
	Test test;
	test.testFunc();
 
	return 0;
}

이렇게 고치니 아래처럼 동작하네요.

Test
testFunc
Transport
MyTransport
MyTransport::transportFunc
~MyTransport
~Transport
~Test

아직 왜 해결이되었는지는 모르겠습니다. -_-; 잘 아시는분 설명 좀 부탁드립니다.

INTERRUPT의 이미지

제가 정말 좋아하는 책, Effective C++(스콧 마이어스 지음, 곽용재 옮김) 항목 7에 이런 내용이 있습니다.
"다형성을 가진 기본 클래스에서는 소멸자를 반드시 가상 소멸자로 선언하자."

다름이 아니라 hyunya77님께서 겪으시는 문제는 기본 클래스인 Transport가 가상 소멸자를 가지지 않아서 생긴 문제입니다.

가상 함수를 사용하셨으니 그게 무엇이며, 어떻게 동작하는지는 이해하셨으리라 생각합니다.
문제는 여기에 있습니다.

void Test::testFunc()
{
printf("%s\n", __func__);

m_trans = new MyTransport();
m_trans->transportFunc();
delete m_trans;
}

delete m_trans;를 수행할 때, 컴파일러는 적합한 소멸자를 찾아 호출해 줘야 합니다.
그런데 소멸자가 가상 함수가 아니라면 이 과정은 정적 바인드가 수행되고, 따라서 m_trans의 타입에 의존합니다,
근데 m_trans는 Transport * 타입이죠. 그래서 컴파일러는 이 포인터가 Transport를 가리키고 있다고 생각하고 Transport를 소멸시키기 위한 코드를 작성합니다.
바로 위에서 MyTransport를 생성해서 집어넣었는데도 말이죠. 컴파일러는 그런 걸 신경쓰지 않아요.
결국 Transport의 소멸자가 호출되기 때문에 MyTransport의 소멸자는 무시당하게 됩니다.

소멸자가 가상 함수로 선언되어야만 m_trans의 타입과 관계 없이 런타임에서 m_trans가 가리키는 객체의 정확한 타입을 알아내고, 그에 적합한 소멸자를 호출할 수 있게 되는 겁니다.

klara의 이미지

C++에서 상속받지 않은 클래스의 기본 소멸자는 무조건 비가상함수입니다.
상속받은 클래스의 경우는 부모 클래스의 소멸자가 가상함수면 가상함수가 되고 비가상함수면 자식클래스의 소멸자도 비가상함수가 됩니다.
처음 올린 예제는 기본 클래스의 소멸자가 선언되어있지 않으므로 기본소멸자가 쓰이고 따라서 이는 비가상함수이기때문에 자식 클래스의 소멸자가 호출되지 않은 겁니다.
두번째 예제는 명시적으로 가상 함수로 소멸자를 선언했기 때문에 해결된 것입니다.

hyunya77의 이미지

소멸자를 왜 보통 가상함수로 선언하는지도 의문이었는데, 이제 그 이유를 알것갔습니다.
시간내서 답글달아주셔서 감사합니다. ^^

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.