В чем разница между виртуальной функцией и функцией виртуального деструктора?

#c #virtual #destructor

#c #виртуальный #деструктор

Вопрос:

 class Base {
    public:
    virtual ~Base () { cout << "Base Dtor" << endl; }
    virtual void doSomething () { cout << "Base do something" << endl; }
};

class Derive : public Base {
    public:
    ~Derive () { cout << "Derive Dtor" << endl; }
    void doSomething () { cout << "Derive do something" << endl; }
};
 

когда я пытаюсь написать какой-то код, например:

 Base* ptr = new Derive;
ptr->doSomething ();
delete ptr;
 

функция doSomething() вызывается правильно. Почему вызывается производный деструктор, а затем вызывается базовый деструктор? Но doSomething() просто вызывайте только версию производного класса. Деструктор и doSomething() тоже функция, но почему они ведут себя по-разному?

Комментарии:

1. Потому что это то, что должны делать деструкторы: уничтожать весь объект, что делается путем вызова деструктора базового класса.

2. Вызов деструктора через указатель базового класса статически вызовет базовый деструктор, если базовый деструктор не virtual является. Но если базовый деструктор есть virtual , то производный деструктор вызывается полиморфно, как и любой другой виртуальный метод. Однако, как и конструкторы, деструкторы отличаются тем, что они всегда вызывают базу автоматически.

Ответ №1:

Деструкторы объектов являются особыми. Да, это функции, но на самом деле они представляют что-то конкретное. А именно, уничтожение объекта.

В вашем примере Derive это объект. Но через наследование Derive вызывается подобъект базового класса Base . То есть для каждого Derive Base в этом объекте также есть жизнь Derive .

Когда вы вызываете конструктор для создания a Derive , соответствующий конструктор будет вызван и для Base подобъекта (в зависимости от того, как вы определили свой Derive конструктор). Таким образом, если вы уничтожаете a Derive , Base живое внутри него также должно быть уничтожено.

virtual Вызов деструктора на самом деле этого не меняет. То, что он virtual делает, позволяет системе правильно запускать цепочку деструкторов. Если бы вы не объявили Base деструктор virtual , то вызов delete указателя базового класса вызывал бы только ~Base . Он не сможет перейти к графу наследования для вызова ~Derive ; delete выражению присваивается Base указатель на удаление, так что это то, что он делает.

Это тот же механизм, что и любой virtual вызов. Если вы не создали обычную функцию virtual -член и вызываете ее по указателю Base класса, вы получаете Base ее версию, даже если существует Derive версия с тем же именем. Вам нужно virtual заставить компилятор перейти к графу наследования и найти правильную функцию для вызова.

Но как только компилятор узнает правильный тип объекта для запуска цепочки деструкторов, эта цепочка уничтожения объектов все равно произойдет. Derive содержит a Base , поэтому для Derive уничтожения a его Base также необходимо уничтожить.

Ответ №2:

Почему вызывается производный деструктор, а затем вызывается базовый деструктор?

Потому что деструктор всегда уничтожает все вложенные объекты. Это включает в себя основы.

Ответ №3:

Вы переопределили doSomething функцию, поэтому она выполняется только для Derive объявленного вами объекта.

Вы можете видеть, что деструкторы имеют разные имена. Когда вы вызываете деструктор какого-либо объекта, автоматически вызывается и деструктор отца.