Форум программистов, компьютерный форум, киберфорум
Наши страницы

С++ для начинающих

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

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

17.04.2011, 01:10. Просмотров 2972. Ответов 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
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
17.04.2011, 01:10
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Как удалить объект по указателю на базовый класс? (C++):

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

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

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

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

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

Как преобразовать указатель на класс к указателю на асбтрактный класс? - C++
Но тут есть одна тонкость- два промежуточных класса. Вот код, надеюсь всё из него понятно. #include <stdio.h> ...

13
ForEveR
В астрале
Эксперт С++
7983 / 4742 / 321
Регистрация: 24.06.2010
Сообщений: 10,545
Завершенные тесты: 3
17.04.2011, 01:26 #2
AndreyBS, Э. А что мешает при нормальном деструкторе просто удалять не парясь с приведениями типов и т.п.? оО
0
AndreyBS
0 / 0 / 0
Регистрация: 17.04.2011
Сообщений: 5
17.04.2011, 01:31  [ТС] #3
Цитата Сообщение от ForEveR Посмотреть сообщение
AndreyBS, Э. А что мешает при нормальном деструкторе просто удалять не парясь с приведениями типов и т.п.? оО
Если не приводить типы, то операция delete _array_of_A[n] вызовет ошибку в памяти. Без приведения типов никак. Сначала должен сработать деструктор В, а уже потом деструктор А. Поэтому удаляя объект, к нему нельзя обращаться, как к А, ведь А не знает о деструкторе В и попросту игнорирует его. Думаю, от сюда и ошибка высвобождения памяти выскакивает.
0
kravam
быдлокодер
1702 / 889 / 45
Регистрация: 04.06.2008
Сообщений: 5,498
17.04.2011, 01:36 #4
Цитата Сообщение от AndreyBS Посмотреть сообщение
Может хотя бы можно узнать тип класса, основываясь на его указателе?
Это вряд ли, ведь указатель суть адрес; как по адресу определить тип переменной ну или объекта, которая там находится? Вряд ли. Извините, если что не так.
0
alex_x_x
бжни
2450 / 1655 / 84
Регистрация: 14.05.2009
Сообщений: 7,162
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];
}
где проблема?
2
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<>
я тоже думаю, что где то в структуре памяти объекта хранится ИД класса. его просто нужно вытащить.
0
alex_x_x
бжни
2450 / 1655 / 84
Регистрация: 14.05.2009
Сообщений: 7,162
17.04.2011, 01:52 #7
Цитата Сообщение от AndreyBS Посмотреть сообщение
По поводу деструктора не получилось. Компилятор ругается. Можно пример?
приведите пример
0
AndreyBS
0 / 0 / 0
Регистрация: 17.04.2011
Сообщений: 5
17.04.2011, 01:58  [ТС] #8
Цитата Сообщение от alex_x_x Посмотреть сообщение
...
где проблема?
Все получилось! Спасибо! Не знал, что виртуальный деструктор так сработает.
0
kravam
быдлокодер
1702 / 889 / 45
Регистрация: 04.06.2008
Сообщений: 5,498
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. "
0
alex_x_x
бжни
2450 / 1655 / 84
Регистрация: 14.05.2009
Сообщений: 7,162
06.05.2011, 23:06 #10
Цитата Сообщение от kravam Посмотреть сообщение
Но деструктор класса B благополучно вызывается и БЕЗ ОБЪЯВЛЕНИЯ его виртуальным.
если деструктор B не будет виртуальным, то он не будет вызван
0
kravam
быдлокодер
1702 / 889 / 45
Регистрация: 04.06.2008
Сообщений: 5,498
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 секунды
хотя он НЕ ВИРТУАЛЬНЫЙ!
0
alex_x_x
бжни
2450 / 1655 / 84
Регистрация: 14.05.2009
Сообщений: 7,162
07.05.2011, 00:01 #12
Цитата Сообщение от kravam Посмотреть сообщение
virtual ~A()
для виртуальности метода достаточно указать его виртуальность в базовом классе, и не открывать потом америку
так что виртуальный он, виртуальный
0
silent_1991
Эксперт С++
4987 / 3044 / 149
Регистрация: 11.11.2009
Сообщений: 7,027
Завершенные тесты: 1
07.05.2011, 00:26 #13
alex_x_x, согласен, достаточно, однако я всегда указываю virtual перед виртуальными методами во всех классах - мне так удобнее.

Не по теме:

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

0
Evg
Эксперт CАвтор FAQ
18251 / 6376 / 438
Регистрация: 30.03.2009
Сообщений: 17,651
Записей в блоге: 28
07.05.2011, 09:05 #14
Цитата Сообщение от alex_x_x Посмотреть сообщение
для виртуальности метода достаточно указать его виртуальность в базовом классе
Сие звучит, возможно, не совсем понятно. Смысл в том, что когда в базовом классе мы объявляем метод или деструктор с ключом virtual, то во всех производных классах virtual пронаследуется из базового независимо от того, напишем мы в производном классе ключ virtual, или нет. В производных классах в таких случаях обычно всё равно пишут ключ virtual - исключительно ради удобства чтения кода
0
07.05.2011, 09:05
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
07.05.2011, 09:05
Привет! Вот еще темы с ответами:

Класс: как обратиться к методу производного класса через итератор на базовый класс? - C++
Есть абстрактный и два порожденных. Хочу создать например list&lt;Base*&gt; list1; затем добавляю себе в список: ...

Как узнать, какого типа объект находится по указателю - C++
Есть массив указателей базового класса, нужно узнать какие типы этих объектов. class Shape{ public: ~Shape(){} virtual void...

Как в функции my_function преобразовать ссылку на базовый класс в ссылку на класс B или С - C++
Всем привет, как в функции my_function преобразовать ссылку на базовый класс в ссылку на класс B или С ? class A { public: A(); ...

Как управлять наследниками через базовый класс - C++
Всем привет)Есть вот одна проблема. Хочу управлять объекты через другие объекты. Допустим есть базовый класс class base { ...


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

Или воспользуйтесь поиском по форуму:
14
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru