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

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

19.10.2016, 23:01. Показов 2661. Ответов 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
9005 / 4706 / 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
12925 / 6793 / 1819
Регистрация: 18.10.2014
Сообщений: 17,190
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
9005 / 4706 / 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
9005 / 4706 / 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
9005 / 4706 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
20.10.2016, 17:51
Цитата Сообщение от cofo Посмотреть сообщение
Почему в моем случае виртуальные деструкторы не нужны?
потому, что деструктора базового класса достаточно. Тут и он не нужен если честно.
cofo, посмотрите совет про self_test и переделайте код. Посмотрите что получилось. Тогда Вы поймёте как вызывается виртуальный деструктор на указателе базового класса.
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12925 / 6793 / 1819
Регистрация: 18.10.2014
Сообщений: 17,190
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
Ответ Создать тему
Новые блоги и статьи
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка.
Programma_Boinc 23.12.2025
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка. Рецензия / Мнение/ Перевод https:/ / **********/ gallery/ thinkpad-x220-tablet-porn-gzoEAjs . . .
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Как объединить две одинаковые БД Access с разными данными
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru