Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.77/13: Рейтинг темы: голосов - 13, средняя оценка - 4.77
0 / 0 / 0
Регистрация: 17.02.2014
Сообщений: 17

Необходимость в использовании виртуальных деструкторов и их правильное использование

19.10.2016, 23:01. Показов 2709. Ответов 11
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Добрый вечер, у меня несколько вопросов по виртуальным деструкторам.

1) В данном примере не используются виртуальные деструкторы, правильно ли это? По идее динамическая память тут не выделяется поэтому можно обойтись без деструкторов, но в аналогичном примере из моего второго вопроса (класс Brain) виртуальные деструкторы почему-то используются. Где правильно? И в каких случаях действительно нужны виртуальные деструкторы?

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <iostream>
#include <string>
 
using namespace std;
 
class Human{
  protected:
    string name;
    int age;
    char sex;
  public:
  /* v Ваш код v */
  Human(string name, int age, char sex) {
    this-> name = name;
    this-> age = age;
    this-> sex = sex;
  }
    
    virtual void Show() {
      cout << name << endl << age << endl << sex << endl;
    }
  
};
 
class Coder: public Human{
  protected:
    float IQ;
  public:
  /* v Ваш код v */
  Coder(string name, int age, char sex, float IQ):Human(name, age, sex) {
    this-> IQ = IQ;
  }
  
  void Show() {
    cout << IQ;
  }
  
};
 
int main(){
  
  Human *human = new Human("Tom", 21, 'M');
  Human *coder = new Coder("Alice", 19, 'F', 150.6f);
  human->Show();
  coder->Show();
  return 0;
}

2) У базового класса есть виртуальный деструктор virtual ~Brain(), у первого наследника вирт. деструктор ~Legs() плюс в конце высвобождается память с помощью delete legs; аналогично со вторым наслеником - ~Eyes() и delete eyes. Виртуальный деструктор нужен, чтобы при удалении объекта удалялась не только часть класса наследника, но и базового. В связи с чем вопрос, нужно ли в конце писать delete brain? И почему?

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <iostream>
 
using namespace std;
 
class Brain{
  public:
    void Start(){
      cout << "Робот успешно запущен\n";
    }
    virtual bool CheckLegs(){
      return false;
    }
    virtual bool CheckEyes(){
      return false;
    }
    /*v Ваш код v*/
    virtual ~Brain(){
      cout << "Робот выключен\n";
    }
};
 
class Legs: public Brain{
  public:
    bool CheckLegs(){
      cout << "Проверка опорнодвигательной системы...\n";
      return true;
    }
    /*v Ваш код v*/
    ~Legs(){
      cout << "Движение робота не возможно\n";
    }
};
 
class Eyes: public Brain{
  public:
    bool CheckEyes(){
      cout << "Проверка работоспособности камеры...\n";
      return true;
    }
  /*v Ваш код v*/
  ~Eyes(){
    cout << "Робот ничего не видит\n";
  }
};
 
int main(){
  Brain *brain = new Brain;
  Brain *legs = new Legs;
  Brain *eyes = new Eyes;
  if (legs->CheckLegs() && eyes->CheckEyes()){
    brain->Start();
  }
  delete legs;  
  delete eyes;  
  return 0;
}
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
19.10.2016, 23:01
Ответы с готовыми решениями:

Правильное использование конструкторов и деструкторов
#include &quot;stdafx.h&quot; #include &lt;iostream&gt; #include &lt;conio.h&gt; using namespace std; class Worker {public: ...

использование деструкторов
добрый день!! спасибо всем на форуме, кто помогает изучать язык с 0 толковыми объяснениями. ведь без обсуждения изучать очень тяжело....

Использование конструторов и деструкторов
Вычислить значение выражения 10^y - x^y + x^n , если х&gt;0. С помощью конструторов и деструкторов. То есть он должен считать так, что...

11
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9007 / 4708 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
19.10.2016, 23:59
Цитата Сообщение от cofo Посмотреть сообщение
Виртуальный деструктор нужен, чтобы при удалении объекта удалялась не только часть класса наследника, но и базового.
Виртуальный деструктор нужен, чтобы при удалении объекта удалялась не только часть принадлежащая базовому классу, но и часть принадлежащая наследнику.
Дело в том что деструктор базового будет вызван в любом случае, а виртуальный деструктор будет вызван именно для того чем наследник отличился. От батька.
В Вашем случае это имеет смысл как учебный тест - посмотреть сообщения, их порядок вывода. Потому что они действительно ничего не освобождают тут.
Хуже другое. Виртуальные методы бессмысленны и беспощадны. Лучше было бы определить в базовом метод
C++
1
virtual bool self_test();
(self это оказывается ыуда )
тогда в наследниках legs протянут ноги, а eyes вытаращат глазья. То есть при вызове self_test через указатели базового класса Вам не нужно будет знать что именно и кто вызывает. Вы будете уверены, что вот тот кто вызывает, так он уж вызовет именно то что ему надо. То есть вытаращенных ног и вытянутых глаз не случится. Во всяком случае не должно.
А указатели надо освобождать (вернее их память). Там и деструкторы вызовутся вдобавок. Хотя main и так всё уничтожит, но для порядку - вызывайте. Причина та же что и у любых указателей на динамическую память: надо.
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12943 / 6810 / 1821
Регистрация: 18.10.2014
Сообщений: 17,235
20.10.2016, 00:41
Лучший ответ Сообщение было отмечено Croessmah как решение

Решение

Цитата Сообщение от cofo Посмотреть сообщение
Виртуальный деструктор нужен, чтобы при удалении объекта удалялась не только часть класса наследника, но и базового.
Виртуальный деструктор нужен только для одного: чтобы правильно удалять (при помощи delete) объект-наследник через указатель на его базу.

C++
1
2
3
4
5
struct Base { ... };
struct  Derived : Base { ... };
...
Base *p = new Derived;
delete p; // Нужен виртуальный деструктор `~Base::Base()`
Если в такой ситуации деструктор невиртуален, то поведение не определено. Нет и быть не может никаких объяснений о том, что произойдет в таком случае, из разряда "чтобы удалялась не только часть класса наследника, но и базового", или "будет утечка памяти", или еще чего. Это все какая-то белиберда. Поведение просто не определено.

Ни в одном из ваших вариантов такого удаления нет. Поэтому формально нигде вам виртуальный деструктор не нужен.

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

Цитата Сообщение от cofo Посмотреть сообщение
В связи с чем вопрос, нужно ли в конце писать delete brain?
Разумеется, нужно.

Цитата Сообщение от cofo Посмотреть сообщение
И почему?
Что значит "почему"? Создали объект - не забывайте и удалить. В программе количество delete должно быть равно количеству new: сколько создали, столько и удаляем.
5
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9007 / 4708 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
20.10.2016, 10:48
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Если в такой ситуации деструктор невиртуален, то поведение не определено. Нет и быть не может никаких объяснений о том, что произойдет в таком случае, из разряда "чтобы удалялась не только часть класса наследника, но и базового", или "будет утечка памяти", или еще чего. Это все какая-то белиберда. Поведение просто не определено.
Строго говоря, да. Поведение будет определяться поведением системы в ситуации, когда указатель типа T1, приведён к типу Т2, а потом на нём запущен delete. В части освобождения памяти, потому как вызова "левого" деструктора не будет. Деструктор базового класса не создаст проблем, а вот несовпадение размеров создаст.
Я написал то, что написал не для проявления глубины знаний. Её и нет если честно. Я пытался объяснить ситуацию в терминах ТС. Так как то что он пытается сказать, свидетельствует о том, что термины ему знакомы, а ситуация (модель в которой они работают) непонятна. Судя по его молчанию, он не переварил сказанного мною. Сказанного Вами и подавно. Или занят очень.
В любом случае, Ваше замечание верно и я благодарен Вам за помощь. Спасибо.
0
Форумчанин
Эксперт CЭксперт С++
 Аватар для MrGluck
8216 / 5047 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
20.10.2016, 12:07
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
В программе количество delete должно быть равно количеству new: сколько создали, столько и удаляем.
Поправочка: если не использовать smart pointer-ы, разумеется.
0
Ушел с форума
Эксперт С++
 Аватар для Убежденный
16481 / 7444 / 1187
Регистрация: 02.05.2013
Сообщений: 11,616
Записей в блоге: 1
20.10.2016, 12:30
Цитата Сообщение от cofo Посмотреть сообщение
Где правильно? И в каких случаях действительно нужны виртуальные деструкторы?
Везде, где объект удаляется через указатель на его предка (так называемое полиморфное
удаление), у предка должен быть (MUST HAVE!!!) виртуальный деструктор. Нарушение этого
требования ведет к неопределенному поведению - UB.

Очень правильно TheCalligrapher написал выше - не должно и не может быть никаких
предположений или объяснений на этот счет, даже если программа успешно компилируется и на
этапе выполнения не вылезает никаких ошибок. Это все до поры. Легко можно привести
реальный, не надуманный, пример, когда нарушение этого правила ведет к аварийному
завершению работы программы на большинстве популярных компиляторов.
3
2549 / 1208 / 358
Регистрация: 30.11.2013
Сообщений: 3,826
20.10.2016, 12:38
MrGluck, нету поправочки - смарт-указатели инкапсулируют delete
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
20.10.2016, 12:42
Цитата Сообщение от Убежденный Посмотреть сообщение
Легко можно привести
реальный, не надуманный, пример, когда нарушение этого правила ведет к аварийному
завершению работы программы на большинстве популярных компиляторов.
http://rextester.com/ERU34818


C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
 
 
struct base 
{
    virtual void ololo()const = 0 ;
};
 
struct der: base 
{
    virtual void ololo()const {}
};
 
struct trololo: base 
{
    virtual void ololo()const {}
};
 
struct example: der, trololo {};
 
 
int main()
{
    std::cout << "Hello, world!\n";
    
    std::cout << "example: undefined behavior\n";
    std::cout << "it resulted in abortion signal";
    std::cout << std::endl;
    
    trololo* p = new example;
    delete p;
}
4
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9007 / 4708 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
20.10.2016, 13:16
Лучший ответ Сообщение было отмечено Croessmah как решение

Решение

Цитата Сообщение от Убежденный Посмотреть сообщение
Очень правильно TheCalligrapher написал выше - не должно и не может быть никаких
предположений или объяснений на этот счет
С одной стороны да. А с другой стороны, посмотрите что пишет ТС. Для него сейчас пора ознакомления с виртуальным наследованием. Причём, несколько преждевременная, так как с указателями он знаком ещё совсем слабо и задаёт вопросы о применении delete для элементарной ситуации. В чём польза предваряющего ознакомления? В том же в чём от предваряющего объявления. То есть, линкуется лучше потом. В голове.
Более того. Знакомясь с концепцией мне, например, вначале важно ответить на вопросы: в чём смысл? какая задача решается?, какова цель? Это всё один вопрос. Иначе я просто не смогу учить. Конечно, нельзя опережать события слишком.
Посмотрите как ТС применил виртуальное наследование. Оно бессмысленно. И пока он не поймёт как оно работает, работу виртуального метода "деструктор" объяснить невозможно. Но объяснить можно на языке близком к его языку. А говоря точно, нужно либо главами писать, либо сформулировать "вещь в себе" которых полно в книгах и которую разберёшь когда их перечитаешь. Тут есть дилемма. Я не призываю опускаться до мычания и сюсюкания, но некоторая мера условности оправдана. Всё к чему мы прикасаемся требует многократного возвращения и уточнения. То есть, если судьба, то человек к этому ещё вернётся.
0
0 / 0 / 0
Регистрация: 17.02.2014
Сообщений: 17
20.10.2016, 14:52  [ТС]
По поводу delete и утечек памяти - разобрался, это код с обучающего сайта и при ознакомлении с ним возник когнитивный диссонанс.
Вы написали следующее:
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Ни в одном из ваших вариантов такого удаления нет. Поэтому формально нигде вам виртуальный деструктор не нужен.
Как написали ниже:
Цитата Сообщение от Убежденный Посмотреть сообщение
Везде, где объект удаляется через указатель на его предка (так называемое полиморфное
удаление), у предка должен быть (MUST HAVE!!!) виртуальный деструктор.
В обоих примерах, которые я привел, объект удаляется через указатель на его предка, например:
C++
1
2
3
4
5
Brain *legs = new Legs;
delete legs;
 
Human *coder = new Coder("Alice", 19, 'F', 150.6f);
delete coder;
Почему в моем случае виртуальные деструкторы не нужны?
0
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9007 / 4708 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
20.10.2016, 17:51
Цитата Сообщение от cofo Посмотреть сообщение
Почему в моем случае виртуальные деструкторы не нужны?
потому, что деструктора базового класса достаточно. Тут и он не нужен если честно.
cofo, посмотрите совет про self_test и переделайте код. Посмотрите что получилось. Тогда Вы поймёте как вызывается виртуальный деструктор на указателе базового класса.
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12943 / 6810 / 1821
Регистрация: 18.10.2014
Сообщений: 17,235
20.10.2016, 18:22
Цитата Сообщение от cofo Посмотреть сообщение
Почему в моем случае виртуальные деструкторы не нужны?
Я ошибся по невнимательности - почему-то посмотрел на имена указателей вместо их типов. Да, конечно, в обоих примерах есть указатели типа предок *, указывающие на потомка. То есть при использовании delete виртуальные деструкторы будут нужны.

Прощу прощения за то, что ввел в заблуждение.

В первом примере просто нет delete (утечка памяти), то есть деструкторы "не нужны", но если устранить утечку, то они понадобятся. Во втором примере виртуальные деструкторы сразу нужны.

Добавлено через 4 минуты
Цитата Сообщение от MrGluck Посмотреть сообщение
Поправочка: если не использовать smart pointer-ы, разумеется.
Я имел в виду не "визуальное" количество new и delete, а, скажем так, "временнОе" их количество. То есть каждое выполнение new-выражения во временнОй последовательности выполнения шагов программы должно иметь соответствующее ему выполнение delete-выражения.

Понятно, конечно, что с "визуальной" точки зрения количество new может не соответствовать количеству delete, так как и первые и последние могут быть завернуты в функции.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
20.10.2016, 18:22
Помогаю со студенческими работами здесь

Использование конструкторов и деструкторов
Решить в консольном режиме: Дан набор из N вещественных чисел. Проверить, образует ли данный набор возрастающую последовательность. Если...

Использование конструкторов и деструкторов
Решить задачу в консольном режиме Даны целые числа K, N и набор из N целых чисел. Если в наборе присутствует число, меньшее K, то...

Возможности модификации программы при использовании виртуальных методов
Приветики, всем доброго время суток!!! Разбираю задачку по PASCAL и наткнулся на ошибку № 3 в 5той строке (TInsertMyDn =...

Простая прога на использование конструкторов и деструкторов в с++ не работает ( не пойму почему (
Вот и дошла я до конструкторов/деструкторов. Но возникла проблема . Первая простая прога- и не работает . Нужно , чтобы просто сначала...

Использование полей подстановок, необходимость и правильность
задаю вопрос не потому что не знаю что это и как использовать, комплекс программ (8) написанных мной и работающих более 10 лет, использует...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
12
Ответ Создать тему
Новые блоги и статьи
делаю науч статью по влиянию грибов на сукцессию
anaschu 13.03.2026
прикрепляю статью
SDL3 для Desktop (MinGW): Создаём пустое окно с нуля для 2D-графики на SDL3, Си и C++
8Observer8 10.03.2026
Содержание блога Финальные проекты на Си и на C++: hello-sdl3-c. zip hello-sdl3-cpp. zip Результат:
Установка CMake и MinGW 13.1 для сборки С и C++ приложений из консоли и из Qt Creator в EXE
8Observer8 10.03.2026
Содержание блога MinGW - это коллекция инструментов для сборки приложений в EXE. CMake - это система сборки приложений. Здесь описаны базовые шаги для старта программирования с помощью CMake и. . .
Как дизайн сайта влияет на конверсию: 7 решений, которые реально повышают заявки
Neotwalker 08.03.2026
Многие до сих пор воспринимают дизайн сайта как “красивую оболочку”. На практике всё иначе: дизайн напрямую влияет на то, оставит человек заявку или уйдёт через несколько секунд. Даже если у вас. . .
Модульная разработка через nuget packages
DevAlt 07.03.2026
Сложившийся в . Net-среде способ разработки чаще всего предполагает монорепозиторий в котором находятся все исходники. При создании нового решения, мы просто добавляем нужные проекты и имеем. . .
Модульный подход на примере F#
DevAlt 06.03.2026
В блоге дяди Боба наткнулся на такое определение: В этой книге («Подход, основанный на вариантах использования») Ивар утверждает, что архитектура программного обеспечения — это структуры,. . .
Управление камерой с помощью скрипта OrbitControls.js на Three.js: Вращение, зум и панорамирование
8Observer8 05.03.2026
Содержание блога Финальная демка в браузере работает на Desktop и мобильных браузерах. Итоговый код: orbit-controls-threejs-js. zip. Сканируйте QR-код на мобильном. Вращайте камеру одним пальцем,. . .
SDL3 для Web (WebAssembly): Синхронизация спрайтов SDL3 и тел Box2D
8Observer8 04.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-sync-physics-sprites-sdl3-c. zip На первой гифке отладочные линии отключены, а на второй включены:. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru