기본 가상 소멸자를 명시 적으로 호출해야합니까?


350

C ++ (가상 소멸자를 사용하여)에서 클래스를 재정의 할 때 상속 클래스에서 가상으로 소멸자를 다시 구현하고 있지만 기본 소멸자를 호출해야합니까?

그렇다면 이런 식으로 생각합니다 ...

MyChildClass::~MyChildClass() // virtual in header
{
    // Call to base destructor...
    this->MyBaseClass::~MyBaseClass();

    // Some destructing specific to MyChildClass
}

내가 맞아?

답변:


469

아니오, 소멸자는 반대 순서로 자동 호출됩니다. (기본 수업 마지막). 기본 클래스 소멸자를 호출하지 마십시오.


순수한 가상 소멸자는 어떻습니까? 내 링커는 상속 된 클래스의 비가 상 소멸자가 끝날 때 호출하려고합니다.
cjcurrie

40
몸이 없으면 순수한 가상 소멸자를 가질 수 없습니다. 그냥 빈 몸을 줘. 일반적인 순수 가상 메서드를 사용하면 소멸자를 사용하여 재정의 함수가 대신 호출되며 모두 소위 호출되므로 본문을 제공해야합니다. = 0은 재정의해야 함을 나타내므로 필요한 경우 여전히 유용한 구문입니다.
Lou Franco

1
이 질문은 관련이 있고 도움을 제공하는 질문 / 15265106 / ca-missing-vtable-error .
Paul-Sebastian Manole

Nick Bolton의 코드가 기본 소멸자를 두 번 호출하지만 세그먼트 delete클래스에 대한 포인터를 두 번 호출 해도 세그먼트 오류가 발생하는 이유는 무엇입니까?
Maggyero

2
잘못된 코드로 인해 분할 오류가 보장되지는 않습니다. 또한 소멸자를 호출해도 메모리가 해제되지 않습니다.
Lou Franco

92

기본 소멸자를 호출 할 필요는 없습니다. 파생 소멸자가 항상 기본 소멸자를 호출합니다. 파괴 명령에 대해서는 여기 관련 답변을 참조하십시오 .

기본 클래스에서 가상 소멸자를 원하는 이유를 이해하려면 아래 코드를 참조하십시오.

class B
{
public:
    virtual ~B()
    {
        cout<<"B destructor"<<endl;
    }
};


class D : public B
{
public:
    virtual ~D()
    {
        cout<<"D destructor"<<endl;
    }
};

할 때 :

B *pD = new D();
delete pD;

그런 다음 B에 가상 소멸자가 없으면 ~ B () 만 호출됩니다. 그러나 가상 소멸자가 있으므로 ~ D ()가 먼저 호출되고 ~ B ()가 호출됩니다.


20
프로그램 (의사) 출력을 포함하십시오. 독자를 도울 것입니다.
Kuldeep Singh Dhaka

@KuldeepSinghDhaka 독자는 wandbox.org/permlink/KQtbZG1hjVgceSlO 에서 볼 수 있습니다 .
돼지

27

다른 사람들이 말한 것 외에도 파생 클래스에서 소멸자를 가상으로 선언 할 필요는 없습니다. 기본 클래스에서와 마찬가지로 소멸자를 가상으로 선언하면 파생 된 모든 소멸자가 선언 여부에 관계없이 가상이됩니다. 다시 말해:

struct A {
   virtual ~A() {}
};

struct B : public A {
   virtual ~B() {}   // this is virtual
};

struct C : public A {
   ~C() {}          // this is virtual too
};

1
~ B가 가상으로 선언되지 않으면 어떻게됩니까? ~ C는 여전히 가상입니까?

5
예. 가상 메소드 (소멸자 만이 아닌)가 가상으로 선언되면 파생 클래스에서 해당 메소드의 모든 대체는 자동으로 가상입니다. 이 경우 ~ B virtual을 선언하지 않더라도 여전히 ~ C입니다.
boycy

1
그러나 기본 클래스에서 해당 메소드의 이름과 매개 변수가 동일한 다른 재정의 된 메소드와 달리 소멸자 이름이 다릅니다. @boycy
Yuan Wen

1
@YuanWen 아니오, (하나만) 파생 소멸자는 항상 기본 클래스 (하나만) 소멸자를 재정의합니다.
boycy

10

아닙니다. Derived에서 Base 메소드를 명시 적으로 호출하여 호출을 '연결'하는 다른 가상 메소드와 달리 컴파일러는 생성자가 호출 된 역순으로 소멸자를 호출하는 코드를 생성합니다.


9

아니요, 기본 클래스 소멸자를 호출하지 마십시오. 다른 사람들이 지적한 것처럼 항상 자동으로 호출되지만 결과가있는 개념 증명이 있습니다.

class base {
public:
    base()  { cout << __FUNCTION__ << endl; }
    ~base() { cout << __FUNCTION__ << endl; }
};

class derived : public base {
public:
    derived() { cout << __FUNCTION__ << endl; }
    ~derived() { cout << __FUNCTION__ << endl; } // adding call to base::~base() here results in double call to base destructor
};


int main()
{
    cout << "case 1, declared as local variable on stack" << endl << endl;
    {
        derived d1;
    }

    cout << endl << endl;

    cout << "case 2, created using new, assigned to derive class" << endl << endl;
    derived * d2 = new derived;
    delete d2;

    cout << endl << endl;

    cout << "case 3, created with new, assigned to base class" << endl << endl;
    base * d3 = new derived;
    delete d3;

    cout << endl;

    return 0;
}

출력은 다음과 같습니다.

case 1, declared as local variable on stack

base::base
derived::derived
derived::~derived
base::~base


case 2, created using new, assigned to derive class

base::base
derived::derived
derived::~derived
base::~base


case 3, created with new, assigned to base class

base::base
derived::derived
base::~base

Press any key to continue . . .

기본 클래스 소멸자를 가상으로 설정하면 사례 3 결과는 사례 1 및 2와 같습니다.


좋은 그림. 파생 클래스에서 기본 클래스 소멸자를 호출하려고하면 "오류 : 'BASE :: BASE ()'호출에 대한 일치하는 함수가 없습니다 <newline> ~ BASE ();와 유사한 컴파일러 오류가 발생합니다. 적어도 이것은 내 g ++ 7.x 컴파일러의 동작입니다.
Kemin Zhou


1

C ++의 소멸자는 Base 클래스 소멸자가 선언 될 때만 생성 순서 (Derived then Base)로 자동 호출 됩니다 .virtual

그렇지 않은 경우 객체 삭제시 기본 클래스 소멸자 만 호출됩니다.

예 : 가상 소멸자가없는 경우

#include <iostream>

using namespace std;

class Base{
public:
  Base(){
    cout << "Base Constructor \n";
  }

  ~Base(){
    cout << "Base Destructor \n";
  }

};

class Derived: public Base{
public:
  int *n;
  Derived(){
    cout << "Derived Constructor \n";
    n = new int(10);
  }

  void display(){
    cout<< "Value: "<< *n << endl;
  }

  ~Derived(){
    cout << "Derived Destructor \n";
  }
};

int main() {

 Base *obj = new Derived();  //Derived object with base pointer
 delete(obj);   //Deleting object
 return 0;

}

산출

Base Constructor
Derived Constructor
Base Destructor

예 : 기본 가상 소멸자 사용

#include <iostream>

using namespace std;

class Base{
public:
  Base(){
    cout << "Base Constructor \n";
  }

  //virtual destructor
  virtual ~Base(){
    cout << "Base Destructor \n";
  }

};

class Derived: public Base{
public:
  int *n;
  Derived(){
    cout << "Derived Constructor \n";
    n = new int(10);
  }

  void display(){
    cout<< "Value: "<< *n << endl;
  }

  ~Derived(){
    cout << "Derived Destructor \n";
    delete(n);  //deleting the memory used by pointer
  }
};

int main() {

 Base *obj = new Derived();  //Derived object with base pointer
 delete(obj);   //Deleting object
 return 0;

}

산출

Base Constructor
Derived Constructor
Derived Destructor
Base Destructor

기본 클래스 소멸자를 virtual그렇지 않으면 선언 하지 않는 것이 좋습니다 . 정의되지 않은 동작이 발생합니다.

참조 : 가상 소멸자

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.