Кто вызывает Деструктор класса, когда оператор удаления используется в множественном наследовании - PullRequest
5 голосов
/ 07 апреля 2010

Этот вопрос может показаться слишком глупым, однако я не нахожу конкретного ответа где-либо еще.

С небольшим знанием того, как работает поздняя привязка, и виртуальным ключевым словом, используемым в наследовании.

Как и в примере кода, когда в случае наследования, когда указатель базового класса, указывающий на объект производного класса, созданный в операторе heap и delete, используется для освобождения памяти, вызывается деструктор производного и базового только по порядку, когда базовый деструктор объявлен виртуальной функцией.

Теперь мой вопрос:

1) Когда деструктор base не является виртуальным, почему проблема не вызова производного dtor возникает только тогда, когда в случае использования оператора «delete» почему бы и нет в случае, указанном ниже:

<code>
derived drvd;
base *bPtr;
bPtr = &drvd; //DTOR called in proper order when goes out of scope.
</p> <p>2) When "delete" operator is used, who is reponsible to call the destructor of the class? The operator delete will have an implementation to call the DTOR ? or complier writes some extra stuff ? If the operator has the implementation then how does it looks like , [I need sample code how this would have been implemented]. </p> <p>3) If virtual keyword is used in this example, how does operator delete now know which DTOR to call?</p> <p>Fundamentaly i want to know who calls the dtor of the class when delete is used.</p> <pre><code><h1> Sample Code </h1> class base { public: base(){ cout<<"Base CTOR called"<<endl; } virtual ~base(){ cout<<"Base DTOR called"<<endl; } }; class derived:public base { public: derived(){ cout<<"Derived CTOR called"<<endl; } ~derived(){ cout<<"Derived DTOR called"<<endl; } };

Я не уверен, что это дубликат, я не смог найти в поиске.

int main () { base * bPtr = new производный ();

delete bPtr;// only when you explicitly try to delete an object
return 0;
</code>

}

Ответы [ 4 ]

2 голосов
/ 07 апреля 2010

+ 1 Хороший вопрос Кстати.

Посмотрите, как работает виртуальный механизм для метода без деструктора, и вы обнаружите, что деструктор ведет себя не иначе.

В игре есть 2 механизма, которые могут немного запутать проблему.Во-первых, механизм, который не является виртуальным, происходит при строительстве и разрушении объекта.Объект создается из базового класса в производный класс, в этом порядке, и при разрушении порядок деструкторов меняется на обратный, поэтому он выводится из базового класса.Ничего нового здесь.

Рассмотрите возможность вызова не виртуального метода на основе указателя класса на объект производного класса, что происходит?Реализация базового класса называется.Теперь рассмотрим вызов виртуального метода из указателя базового класса на объект производного класса. Что происходит?Производная версия метода называется.Ничего, что вы еще не знали.

Давайте теперь рассмотрим сценарий деструктора.Вызовите delete для указателя базового класса на объект производного класса, который имеет не виртуальный деструктор.Деструктор базового класса вызывается, и если базовый класс был получен из другого класса, то его деструктор будет вызван следующим.Поскольку виртуальный механизм не задействован, производный деструктор не будет вызываться, потому что уничтожение начинается с деструктора, который вы вызываете в иерархии, и переходит к базовому классу.

Теперь рассмотрим виртуальный деструктор.дело.delete вызывается на основе указателя класса на объект производного класса.Что происходит, когда вы вызываете любой виртуальный метод на указателе базового класса?Производная версия вызывается.Так называется наш деструктор производного класса.Что происходит во время уничтожения, объект разрушается от производного деструктора до базового класса, но на этот раз мы начали уничтожение на уровне производного класса из-за механизма виртуального метода.

Почему стековый объект с не виртуальнымили виртуальный деструктор разрушается от производного до базового класса, когда выходит из области видимости?Потому что в этом случае вызывается деструктор объявленного класса, а виртуальный механизм не имеет к этому никакого отношения.

2 голосов
/ 07 апреля 2010
  1. Это связано с тем, что в этом случае компилятору известно все об объекте, подлежащем уничтожению, который в данном случае равен drvd и имеет тип derived. Когда drvd выходит из области видимости, компилятор вставляет код для вызова его деструктора

  2. delete - ключевое слово для компилятора. Когда компилятор видит удаление, он вставляет код для вызова деструктора и код для вызова operator delete для освобождения памяти. Пожалуйста, имейте в виду, что keyword delete и operater delete различны.

  3. Когда компилятор видит, что keyword delete используется для указателя, он должен сгенерировать код для его правильного уничтожения. Для этого ему нужно знать информацию о типе указателя. Единственное, что компилятор знает о указателе, это тип указателя, а не тип объекта, на который указывает указатель. Объект, на который указывает указатель, может быть базовым классом или производным классом. В некоторых случаях тип объекта может быть очень четко определен, например

void fun()
{
    Base *base= new Derived(); 
    delete base;
}

Но в большинстве случаев это не так, например, этот

void deallocate(Base *base)
{
    delete base;
}

Таким образом, компилятор не знает, какой деструктор вызывать из base или производного. Вот так то и работает

  1. Если базовый класс не имеет виртуальной функции (функция-член или деструктор). Он напрямую вставляет код для вызова деструктора базового класса
  2. Если базовый класс имеет виртуальные функции, то компилятор получает информацию о destructer из vtable.
    1. Если деструктор не виртуальный. Vtable будет иметь адрес базового деструктора и тот, который будет называться. Это неправильно, поскольку здесь не вызывается надлежащий деструктор. Вот почему всегда рекомендуется объявлять деструктор базового класса как виртуальный
    2. Если деструктор виртуальный, у vtable будет правильный адрес деструктора, и компилятор вставит туда правильный код
1 голос
/ 07 апреля 2010
  1. Вы создаете экземпляр производного типа, когда он выходит из области видимости, он вызывает деструктор, виртуальный или нет.
  2. Компилятор сгенерирует код, который вызывает деструкторы. Это не все происходит во время компиляции. Генерация кода делает, но посмотрите, что адрес dtor происходит во время выполнения. Подумайте о случае, когда у вас более 1 производного типа, и вы выполняете удаление, используя базовый указатель.
  3. Деструктор базового класса должен быть виртуальным, чтобы полиморфное удаление вызывало dtor производного типа.

Если вы хотите узнать больше, попробуйте перегрузить new и удалить.

1 голос
/ 07 апреля 2010

Компилятор генерирует весь необходимый код для вызова деструкторов в правильном порядке, будь то объект стека или переменная-член, выходящая из области видимости, или удаляемый объект кучи.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...