То, кто называет Деструктор класса, когда оператор удаляет, используется во множественном наследовании

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

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

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

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

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


derived drvd;
base *bPtr;
bPtr = &drvd; //DTOR called in proper order when goes out of scope.

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].

3) If virtual keyword is used in this example, how does operator delete now know which DTOR to call?

Fundamentaly i want to know who calls the dtor of the class when delete is used.

<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;
     }
};

I'm not sure if this is a duplicate, I couldn't find in search.

int main() { base *bPtr = new derived();

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

}

5
задан dicaprio 29 December 2011 в 10:52
поделиться

4 ответа

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

1
ответ дан 14 December 2019 в 13:31
поделиться

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

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

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

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

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

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

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

2
ответ дан 14 December 2019 в 13:31
поделиться
  1. Вы создаете экземпляр производного типа, когда он выходит за пределы области видимости, он вызывает деструктор, виртуальный или нет.
  2. Компилятор сгенерирует код, который вызовет деструкторы. Не все это происходит во время компиляции. Генерация кода делает, но поиск адреса dtor происходит во время выполнения. Подумайте о случае, когда у вас более 1 производного типа, и вы выполняете удаление с помощью базового указателя.
  3. Деструктор базового класса должен быть виртуальным, чтобы полиморфное удаление вызывало dtor производного типа.

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

1
ответ дан 14 December 2019 в 13:31
поделиться
  1. Это связано с тем, что в этом случае компилятор знает все об объекте, подлежащем уничтожению, который в данном случае является drvd и относится к типу производному . Когда drvd выходит за пределы области видимости, компилятор вставляет код для вызова своего деструктора

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

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

 void fun () 
 {
Base * base = new Derived (); 
удалить базу; 
} 
 

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

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

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

  1. Если базовый класс не имеет виртуальной функции (функции-члена или деструктора). Он напрямую вставляет код для вызова деструктора базового класса
  2. . Если базовый класс имеет виртуальные функции, то компилятор берет информацию деструктора из vtable.
    1. Если деструктор не виртуальный. В vtable будет адрес базового деструктора, и это то, что будет вызываться. Это неправильно, поскольку здесь не вызывается соответствующий деструктер. Вот почему всегда рекомендуется объявлять деструктор базового класса как виртуальный
    2. . Если деструктор виртуальный, vtable будет иметь правильный адрес деструктора, и компилятор вставит туда правильный код
2
ответ дан 14 December 2019 в 13:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: