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

Как удалить объект по указателю на базовый класс?

17.04.2011, 01:10. Показов 6003. Ответов 13
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Допустим есть несколько классов:

// абстрактный класс - введен для управления наследниками
C++
1
2
3
class A{
... 
}
// рабочий класс 1
C++
1
2
3
class B: virtual public A{
... 
}
// рабочий класс 2
C++
1
2
3
class С: virtual public A{
... 
}
// контейнер - управляет всеми рабочими классами через класс А
C++
1
2
3
4
5
6
7
8
9
class D
A *_array_of_A[];
...
 _array_of_A[0] = new B;
 _array_of_A[1] = new C;
...
delete (B *)_array_of_A[0];
delete (C *)_array_of_A[1];
}
Вопрос: можно ли удалить объект класса B или C, не зная тип класса, но имея указатель на их базовый класс А?

Это нужно, чтобы удалять объекты из массива _array_of_A "универсальным способом". Можно, конечно, ввести в класс А переменную Type и удалять по условию:
C++
1
2
3
4
switch(_array_of_A[n]->Type){
case TypeA: delete (A *)_array_of_A[n]; break;
case TypeB: delete (B *)_array_of_A[n]; break;
}
Это не красиво. Может как-то еще это можно сделать? Может хотя бы можно узнать тип класса, основываясь на его указателе?

 Комментарий модератора 
Используйте теги форматирования кода!
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
17.04.2011, 01:10
Ответы с готовыми решениями:

Как удалить объект класс из кучи по указателю?
Как удалить экземпляр класса из кучи по указателю? Есть простенький код: запускает два потока, один выделяет место для объектов и...

Как удалить базовый объект?
Пишу под symbian, здесь Mbase вроде интерфейсов C#: class Mbase { virtual void foo1()=0; virtual void foo2()=0; virtual ...

По указателю на базовый класс сделать копию объекта
Добрый день! Есть следующая задачка: есть абстрактный класс А, от которого унаследовано много наследников. Необходимо по по указателю на...

13
В астрале
Эксперт С++
 Аватар для ForEveR
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
17.04.2011, 01:26
AndreyBS, Э. А что мешает при нормальном деструкторе просто удалять не парясь с приведениями типов и т.п.? оО
0
0 / 0 / 0
Регистрация: 17.04.2011
Сообщений: 5
17.04.2011, 01:31  [ТС]
Цитата Сообщение от ForEveR Посмотреть сообщение
AndreyBS, Э. А что мешает при нормальном деструкторе просто удалять не парясь с приведениями типов и т.п.? оО
Если не приводить типы, то операция delete _array_of_A[n] вызовет ошибку в памяти. Без приведения типов никак. Сначала должен сработать деструктор В, а уже потом деструктор А. Поэтому удаляя объект, к нему нельзя обращаться, как к А, ведь А не знает о деструкторе В и попросту игнорирует его. Думаю, от сюда и ошибка высвобождения памяти выскакивает.
0
быдлокодер
 Аватар для kravam
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,705
17.04.2011, 01:36
Цитата Сообщение от AndreyBS Посмотреть сообщение
Может хотя бы можно узнать тип класса, основываясь на его указателе?
Это вряд ли, ведь указатель суть адрес; как по адресу определить тип переменной ну или объекта, которая там находится? Вряд ли. Извините, если что не так.
0
бжни
 Аватар для alex_x_x
2473 / 1684 / 135
Регистрация: 14.05.2009
Сообщений: 7,162
17.04.2011, 01:48
виртуальный деструктор же
зачем кстати virtual public?

Добавлено через 2 минуты
Цитата Сообщение от kravam Посмотреть сообщение
как по адресу определить тип переменной ну или объекта, которая там находится? Вряд ли. Извините, если что не так.
легко, так же как вызываются виртуальные методы
для полиморфных классов работает приведения dynamic_cast<>

Добавлено через 8 минут
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>
 
#define I_D std::cout << __FUNCTION__ << std::endl;
 
class C
{
public:
   C(){ I_D; }
   ~C(){ I_D; }
};
 
class A
{
public:
  A()
  {
     I_D;
  }
  virtual ~A()
  {
     I_D;
  }
};
 
class B : public A{
public:
  B()
  {
     I_D;
  }
  ~B()
  {
     I_D;
  }
private:
  C m_c;
};
 
int main()
{
  A* a = new B;
  A* arr[10];
  arr[0] = new A;
  arr[1] = new B;
  delete arr[0];
  delete arr[1];
}
где проблема?
2
0 / 0 / 0
Регистрация: 17.04.2011
Сообщений: 5
17.04.2011, 01:50  [ТС]
Цитата Сообщение от alex_x_x Посмотреть сообщение
виртуальный деструктор же
зачем кстати virtual public?
Планировал из классов В и С сделать надстройку типа
class E: public B, public C
На сколько я понимаю, в таком случае в класс E войдет только один экземпляр класса А, т.к. он подключался через virtual public

По поводу деструктора не получилось. Компилятор ругается. Можно пример?


Цитата Сообщение от alex_x_x Посмотреть сообщение
легко, так же как вызываются виртуальные методы
для полиморфных классов работает приведения dynamic_cast<>
я тоже думаю, что где то в структуре памяти объекта хранится ИД класса. его просто нужно вытащить.
0
бжни
 Аватар для alex_x_x
2473 / 1684 / 135
Регистрация: 14.05.2009
Сообщений: 7,162
17.04.2011, 01:52
Цитата Сообщение от AndreyBS Посмотреть сообщение
По поводу деструктора не получилось. Компилятор ругается. Можно пример?
приведите пример
0
0 / 0 / 0
Регистрация: 17.04.2011
Сообщений: 5
17.04.2011, 01:58  [ТС]
Цитата Сообщение от alex_x_x Посмотреть сообщение
...
где проблема?
Все получилось! Спасибо! Не знал, что виртуальный деструктор так сработает.
0
быдлокодер
 Аватар для kravam
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,705
06.05.2011, 23:00
У меня возник один вопрос, вот в книге я прочёл:


"В создании и уничтожении объектов имеется одно существенное отличие. Создавая объект, мы всегда точно знаем, какому классу он принадлежит. При уничтожении это не всегда известно.
C++
1
2
3
4
5
6
7
Item* itptr;
if (type == "book")
     itptr = new Book();
else
     itptr = new Magazin();
. . .
delete itptr;
Во время компиляции неизвестно, каким будет значение переменной type и, соответственно, объект какого класса удаляется операцией delete. Поэтому компилятор может вставить вызов только деструктора базового класса."


А в этой теме мы наблюдаем, что для удаления производного класса НЕОБЯЗАТЕЛЬНО наличие виртуального деструктора. Конкретнее, здесь: (сообщение N 5)

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>
 
#define I_D std::cout << __FUNCTION__ << std::endl;
 
class C
{
public:
   C(){ I_D; }
   ~C(){ I_D; }
};
 
class A
{
public:
  A()
  {
     I_D;
  }
  virtual ~A()
  {
     I_D;
  }
};
 
class B : public A{
public:
  B()
  {
     I_D;
  }
  ~B()
  {
     I_D;
  }
private:
  C m_c;
};
 
int main()
{
  A* a = new B;
  A* arr[10];
  arr[0] = new A;
  arr[1] = new B;
  delete arr[0];
  delete arr[1];
}
То есть чтобы всё было ОК, необходимо чтобы тут
C++
1
2
3
4
5
6
7
8
9
10
class B : public A{
public:
  B()
  {
     I_D;
  }
  ~B()
  {
     I_D;
  }
Было так:
C++
1
2
3
4
5
6
7
8
9
10
class B : public A{
public:
  B()
  {
     I_D;
  }
  virtual ~B()
  {
     I_D;
  }
Но деструктор класса B благополучно вызывается и БЕЗ ОБЪЯВЛЕНИЯ его виртуальным. Вот, хочу узнать, в чём дело- автор книги ошибся или ещё что.

Добавлено через 44 секунды
Ещё в книге написано:
"Для того чтобы все необходимые деструкторы были вызваны, нужно воспользоваться виртуальным механизмом – объявить деструктор как в базовом классе, так и в производном, как virtual. "
0
бжни
 Аватар для alex_x_x
2473 / 1684 / 135
Регистрация: 14.05.2009
Сообщений: 7,162
06.05.2011, 23:06
Цитата Сообщение от kravam Посмотреть сообщение
Но деструктор класса B благополучно вызывается и БЕЗ ОБЪЯВЛЕНИЯ его виртуальным.
если деструктор B не будет виртуальным, то он не будет вызван
0
быдлокодер
 Аватар для kravam
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,705
06.05.2011, 23:20
А он именно что вызван в данном коде, вот я упростил код:
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
#include <windows.h>
#include <iostream>
using namespace std;
 
#define I_D std::cout << __FUNCTION__ << std::endl;
 
class A
{
public:
  A()
  {
     I_D;
  }
  virtual ~A()
  {
     I_D;
  }
};
 
class B : public A{
public:
  B()
  {
     I_D;
  }
  ~B()
  {
     cout<< "деструктор B!"<< endl;
  }
};
 
int main()
{
 SetConsoleCP(1251);
 SetConsoleOutputCP(1251);
  A* arr;
  arr = new B;
  delete arr;
  getchar ();
}

И вывод:
C++
1
2
3
4
A
B
деструктор B!
~A
Вот и всё, вот написано, что должен быть вызван только деструктор базового класса, а вызывается деструктор производного!

Добавлено через 23 секунды
хотя он НЕ ВИРТУАЛЬНЫЙ!
0
бжни
 Аватар для alex_x_x
2473 / 1684 / 135
Регистрация: 14.05.2009
Сообщений: 7,162
07.05.2011, 00:01
Цитата Сообщение от kravam Посмотреть сообщение
virtual ~A()
для виртуальности метода достаточно указать его виртуальность в базовом классе, и не открывать потом америку
так что виртуальный он, виртуальный
0
Эксперт С++
5058 / 3118 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
07.05.2011, 00:26
alex_x_x, согласен, достаточно, однако я всегда указываю virtual перед виртуальными методами во всех классах - мне так удобнее.

Не по теме:

Хотя, возможно, вырвал из контекста, всю тему не читал)))

0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
07.05.2011, 09:05
Цитата Сообщение от alex_x_x Посмотреть сообщение
для виртуальности метода достаточно указать его виртуальность в базовом классе
Сие звучит, возможно, не совсем понятно. Смысл в том, что когда в базовом классе мы объявляем метод или деструктор с ключом virtual, то во всех производных классах virtual пронаследуется из базового независимо от того, напишем мы в производном классе ключ virtual, или нет. В производных классах в таких случаях обычно всё равно пишут ключ virtual - исключительно ради удобства чтения кода
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
07.05.2011, 09:05
Помогаю со студенческими работами здесь

Указателю на базовый класс присвоить адрес производного класса
class Point { public: Point(float a=0, float b=0) { x=a; y=b; } protected: float x; float y; };

Создание объекта произвольного класса по указателю на базовый класс
Есть некий абстрактный базовый класс . Мы знаем , что от этого базового класса будет образовано несколько конкретных производных классов...

Присвоение указателю на базовый класс адреса производного класса
Когда наследую как public,всё норм,как private - ошибка. Как сделать тогда,чтобы открылся конструктор? Base :: Base(); Не помогает ...

typeid определяет тип указателя на базовый класс, как тип "базовый класс". Вне зависимости от присвоенного ему значения
Вот код: #include &lt;iostream&gt; #include &lt;string&gt; #include &lt;conio.h&gt; #include &lt;windows.h&gt; #include &lt;typeinfo&gt; using...

Как вернуть объект по указателю
У меня есть функция QStandardItemModel set_model(QStandardItemModel*a) { return a; } Компилятор ругается, что не может...


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

Или воспользуйтесь поиском по форуму:
14
Ответ Создать тему
Новые блоги и статьи
модель ЗдравоСохранения 8. Подготовка к разному выполнению заданий
anaschu 08.04.2026
https:/ / github. com/ shumilovas/ med2. git main ветка * содержимое блока дэлэй из старой модели теперь внутри зайца новой модели 8ATzM_2aurI
Блокировка документа от изменений, если он открыт у другого пользователя
Maks 08.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа, разработанного в конфигурации КА2. Задача: запретить редактирование документа, если он открыт у другого пользователя. / / . . .
Система безопасности+живучести для сервера-слоя интернета (сети). Двойная привязка.
Hrethgir 08.04.2026
Далее были размышления о системе безопасности. Сообщения с наклонным текстом - мои. А как нам будет можно проверить, что ссылка наша, а не подделана хулиганами, которая выбросит на другую ветку и. . .
Модель ЗдрввоСохранения 7: больше работников, больше ресурсов.
anaschu 08.04.2026
работников и заданий может быть сколько угодно, но настроено всё так, что используется пока что только 20% kYBz3eJf3jQ
Дальние перспективы сервера - слоя сети с космологическим дизайном интефейса карты и логики.
Hrethgir 07.04.2026
Дальнейшее ближайшее планирование вывело к размышлениям над дальними перспективами. И вот тут может быть даже будут нужны оценки специалистов, так как в дальних перспективах всё может очень сильно. . .
Горе от ума
kumehtar 07.04.2026
Эта мне ментальная установка, что вот прямо сейчас, мол, мне для полного счастья не хватает (нужное вписать), и когда я этого достигну - тогда и полный кайф. Одна из самых сильных ловушек на пути. . . .
Использование значений реквизитов справочника в документе, с определенными условиями и правами
Maks 07.04.2026
1. Контроль срока действия договора Алгоритм из решения ниже реализован на примере нетипового документа "ЗаявкаНаРаботу", разработанного в конфигурации КА2. Задача: уведомлять пользователя, если. . .
Доступность команды формы по условию
Maks 07.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: сделать доступной кнопку (команда формы "ЗавершитьСписание") при. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru