Форум программистов, компьютерный форум CyberForum.ru

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

Восстановить пароль Регистрация
 
Рейтинг: Рейтинг темы: голосов - 20, средняя оценка - 4.70
AndreyBS
0 / 0 / 0
Регистрация: 17.04.2011
Сообщений: 5
17.04.2011, 01:10     Как удалить объект по указателю на базовый класс? #1
Допустим есть несколько классов:

// абстрактный класс - введен для управления наследниками
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;
}
Это не красиво. Может как-то еще это можно сделать? Может хотя бы можно узнать тип класса, основываясь на его указателе?

 Комментарий модератора 
Используйте теги форматирования кода!
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
17.04.2011, 01:26     Как удалить объект по указателю на базовый класс? #2
AndreyBS, Э. А что мешает при нормальном деструкторе просто удалять не парясь с приведениями типов и т.п.? оО
AndreyBS
0 / 0 / 0
Регистрация: 17.04.2011
Сообщений: 5
17.04.2011, 01:31  [ТС]     Как удалить объект по указателю на базовый класс? #3
Цитата Сообщение от ForEveR Посмотреть сообщение
AndreyBS, Э. А что мешает при нормальном деструкторе просто удалять не парясь с приведениями типов и т.п.? оО
Если не приводить типы, то операция delete _array_of_A[n] вызовет ошибку в памяти. Без приведения типов никак. Сначала должен сработать деструктор В, а уже потом деструктор А. Поэтому удаляя объект, к нему нельзя обращаться, как к А, ведь А не знает о деструкторе В и попросту игнорирует его. Думаю, от сюда и ошибка высвобождения памяти выскакивает.
kravam
быдлокодер
 Аватар для kravam
1512 / 872 / 44
Регистрация: 04.06.2008
Сообщений: 5,271
17.04.2011, 01:36     Как удалить объект по указателю на базовый класс? #4
Цитата Сообщение от AndreyBS Посмотреть сообщение
Может хотя бы можно узнать тип класса, основываясь на его указателе?
Это вряд ли, ведь указатель суть адрес; как по адресу определить тип переменной ну или объекта, которая там находится? Вряд ли. Извините, если что не так.
alex_x_x
бжни
 Аватар для alex_x_x
2441 / 1646 / 84
Регистрация: 14.05.2009
Сообщений: 7,163
17.04.2011, 01:48     Как удалить объект по указателю на базовый класс? #5
виртуальный деструктор же
зачем кстати 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];
}
где проблема?
AndreyBS
0 / 0 / 0
Регистрация: 17.04.2011
Сообщений: 5
17.04.2011, 01:50  [ТС]     Как удалить объект по указателю на базовый класс? #6
Цитата Сообщение от alex_x_x Посмотреть сообщение
виртуальный деструктор же
зачем кстати virtual public?
Планировал из классов В и С сделать надстройку типа
class E: public B, public C
На сколько я понимаю, в таком случае в класс E войдет только один экземпляр класса А, т.к. он подключался через virtual public

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


Цитата Сообщение от alex_x_x Посмотреть сообщение
легко, так же как вызываются виртуальные методы
для полиморфных классов работает приведения dynamic_cast<>
я тоже думаю, что где то в структуре памяти объекта хранится ИД класса. его просто нужно вытащить.
alex_x_x
бжни
 Аватар для alex_x_x
2441 / 1646 / 84
Регистрация: 14.05.2009
Сообщений: 7,163
17.04.2011, 01:52     Как удалить объект по указателю на базовый класс? #7
Цитата Сообщение от AndreyBS Посмотреть сообщение
По поводу деструктора не получилось. Компилятор ругается. Можно пример?
приведите пример
AndreyBS
0 / 0 / 0
Регистрация: 17.04.2011
Сообщений: 5
17.04.2011, 01:58  [ТС]     Как удалить объект по указателю на базовый класс? #8
Цитата Сообщение от alex_x_x Посмотреть сообщение
...
где проблема?
Все получилось! Спасибо! Не знал, что виртуальный деструктор так сработает.
kravam
быдлокодер
 Аватар для kravam
1512 / 872 / 44
Регистрация: 04.06.2008
Сообщений: 5,271
06.05.2011, 23:00     Как удалить объект по указателю на базовый класс? #9
У меня возник один вопрос, вот в книге я прочёл:


"В создании и уничтожении объектов имеется одно существенное отличие. Создавая объект, мы всегда точно знаем, какому классу он принадлежит. При уничтожении это не всегда известно.
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. "
alex_x_x
бжни
 Аватар для alex_x_x
2441 / 1646 / 84
Регистрация: 14.05.2009
Сообщений: 7,163
06.05.2011, 23:06     Как удалить объект по указателю на базовый класс? #10
Цитата Сообщение от kravam Посмотреть сообщение
Но деструктор класса B благополучно вызывается и БЕЗ ОБЪЯВЛЕНИЯ его виртуальным.
если деструктор B не будет виртуальным, то он не будет вызван
kravam
быдлокодер
 Аватар для kravam
1512 / 872 / 44
Регистрация: 04.06.2008
Сообщений: 5,271
06.05.2011, 23:20     Как удалить объект по указателю на базовый класс? #11
А он именно что вызван в данном коде, вот я упростил код:
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 секунды
хотя он НЕ ВИРТУАЛЬНЫЙ!
alex_x_x
бжни
 Аватар для alex_x_x
2441 / 1646 / 84
Регистрация: 14.05.2009
Сообщений: 7,163
07.05.2011, 00:01     Как удалить объект по указателю на базовый класс? #12
Цитата Сообщение от kravam Посмотреть сообщение
virtual ~A()
для виртуальности метода достаточно указать его виртуальность в базовом классе, и не открывать потом америку
так что виртуальный он, виртуальный
silent_1991
Эксперт C++
4938 / 3014 / 149
Регистрация: 11.11.2009
Сообщений: 7,024
Завершенные тесты: 1
07.05.2011, 00:26     Как удалить объект по указателю на базовый класс? #13
alex_x_x, согласен, достаточно, однако я всегда указываю virtual перед виртуальными методами во всех классах - мне так удобнее.

Не по теме:

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

MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
07.05.2011, 09:05     Как удалить объект по указателю на базовый класс?
Еще ссылки по теме:

C++ Как через базовый класс вызывать виртуальную функцию во всех потомках?
Как при помощи указателя на базовый класс обратится к полю наследуемого класса? C++
C++ Как в функции my_function преобразовать ссылку на базовый класс в ссылку на класс B или С

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

Или воспользуйтесь поиском по форуму:
Evg
Эксперт С++Автор FAQ
 Аватар для Evg
16832 / 5253 / 322
Регистрация: 30.03.2009
Сообщений: 14,145
Записей в блоге: 26
07.05.2011, 09:05     Как удалить объект по указателю на базовый класс? #14
Цитата Сообщение от alex_x_x Посмотреть сообщение
для виртуальности метода достаточно указать его виртуальность в базовом классе
Сие звучит, возможно, не совсем понятно. Смысл в том, что когда в базовом классе мы объявляем метод или деструктор с ключом virtual, то во всех производных классах virtual пронаследуется из базового независимо от того, напишем мы в производном классе ключ virtual, или нет. В производных классах в таких случаях обычно всё равно пишут ключ virtual - исключительно ради удобства чтения кода
Yandex
Объявления
07.05.2011, 09:05     Как удалить объект по указателю на базовый класс?
Ответ Создать тему
Опции темы

Текущее время: 00:48. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru