Форум: Форум C++Разное
Новые темы: 00
MySQL на примерах. Авторы: Кузнецов М.В., Симдянов И.В. Объектно-ориентированное программирование на PHP. Авторы: Кузнецов М.В., Симдянов И.В. PHP 5. На примерах. Авторы: Кузнецов М.В., Симдянов И.В., Голышев С.В. Самоучитель PHP 5 / 6 (3 издание). Авторы: Кузнецов М.В., Симдянов И.В. Самоучитель MySQL 5. Авторы: Кузнецов М.В., Симдянов И.В.
ВСЕ НАШИ КНИГИ
Консультационный центр SoftTime

Форум C++

Выбрать другой форум

 

Здравствуйте, Посетитель!

вид форума:
Линейный форум Структурный форум

тема: Очередь объектов
 
 автор: alex19921992   (18.03.2007 в 08:26)   письмо автору
 
 

Есть несколько вопросов:
1.
Я хочу создать очередь 3Д-объектов, причем количество вершин не определено.
Можно ли сделать так:

struct point{float x,y,z;};
class 3dobject
{
public:
point* vertex;
3dobject* next;
3dobject* prev;
/*тут типа функции создания, конструкторы-деструкторы, и т.д.*/
};
3dobject*first;
3dobject*last;
3dobject*current;

Могу ли я создать сначала очередь, а потом каждому элементу считывать вершины из файла, определять длину массива vertex и потом выделять память под сам массив:

current=new 3dobject; // создали объект
last->next=current; // связали указатели
last=current; // сделали новый элемент последним
last->vertex=new point[10]; //создали 10 вершин. можно ли так делать???


------------------------
И еще вопрос: нужно сделать очередь разных объектов, например
в одном объекте 1 массив вершин, а в другом - 2 массива. То есть нужен универсальный указатель на 2 разных объекта. Возможно ли такое?

  Ответить  
 
 автор: cheops   (18.03.2007 в 13:28)   письмо автору
 
   для: alex19921992   (18.03.2007 в 08:26)
 

В общем можно, но надёжнее и быстрее было бы воспользоваться готовыми контейнерами STL, например, <list>.

  Ответить  
 
 автор: oleg_alexeev   (18.03.2007 в 19:32)   письмо автору
 
   для: alex19921992   (18.03.2007 в 08:26)
 

>> ... нужен универсальный указатель на 2 разных объекта. Возможно ли такое?

Здесь надо воспользоваться наследованием. Пусть эти 2 разных объекта будут производными от
одного базового класса. Тогда этим универсальным указателем будет указатель на базовый класс.
В очередь или список надо помещать именно его.


struct Base
{
  enum Type {TYPE_ONE, TYPE_TWO};

  Type m_type;

  static Base *Create();

  virtual ~Base();
};

struct Derived1 : public Base
{
  Derived1();
  virtual ~Derived1();
}

struct Derived2 : public Base
{
  Derived2();
  virtual ~Derived2();
}


Здесь очень важной является функция Create(). Это так называемая фабрика классов. Именно
она создает объекты классов Derived1 и Derived2 (считывая информацию для создания с диска,
например).

Работать с этими разными классами можно либо прочитав реальный тип объекта из поля m_type
и сделав явное приведение к нужному типу, либо полностью скрыть все данные объекта
(объявив их приватными) и работать с объектом только через виртуальные методы.

Хотя, если объекты отличаются только числом элементов в массиве, иерархия классов не
нужна. Но все равно придется завести поле, в котором хранится тип объекта.
И функции конструирования и рисования должны работать по разному, в зависимости от
типа объекта.

  Ответить  
 
 автор: alex19921992   (19.03.2007 в 09:05)   письмо автору
 
   для: oleg_alexeev   (18.03.2007 в 19:32)
 

принцип в общем понятен, спасибо.
но есть некоторые неясности...
слово virtual перед деструктором - это обязательно? что значит это слово? И вот struct Derived2 : public Base - типа public - это предок, да? и наверно не структ, а класс?

  Ответить  
 
 автор: Фитч   (19.03.2007 в 09:20)   письмо автору
 
   для: alex19921992   (19.03.2007 в 09:05)
 

1. struct и class на деле отличаются в основном уровнем доступа по умолчанию (public для struct и private для class). Struct - объявление в стиле СИ, оно используется достаточно часто
2. Деструкторы лучше делать виртуальными, чтобы при уничтожении объекта был вызван именно деструктор подкласса, а не родителя.

  Ответить  
 
 автор: alex19921992   (19.03.2007 в 11:19)   письмо автору
 
   для: Фитч   (19.03.2007 в 09:20)
 

Вот я знаю, что конструктор инициализирует объект, т.е. дает начальные значения переменным, ну и если объект динамический, то выделяет память под него. А деструктор? Только удалить память и перенаправить указатели в очереди?(если объект динамический).
Так что же значит слово virtual?

  Ответить  
 
 автор: Фитч   (19.03.2007 в 11:33)   письмо автору
 
   для: alex19921992   (19.03.2007 в 11:19)
 

> Так что же значит слово virtual?
Суть такая: если в базовом классе есть функции, объявленные с virtual (необязательно конструктор/деструктор), а в подклассе они переопределены, то если вызвать этот метод базового класса, то на этапе исполнения будет решаться, метод какого класса (базового или кого-то из наследников) будет вызван (полиморфизм, позднее связывание - знакомы?) Для ясности пример:

struct Base
{
 virtual void showMessage()
 {
  fprintf(stdout,"Message from Base!");
 }
};
 
struct SubClass : public Base
{
 virtual void showMessage()
 {
  fprintf(stdout,"Message from Subclass");
 }
};

void alert(Base* o)
{
 o->showMessage();
}

/* ... */

Base* b = new Base;
SubClass* s = new SubClass;

alert(b);
alert(s);
}

Будет выведено:
Message from Base!
Message from subclass

В случае с вашими классами это будет нужно для корректной работы деструктора в завизимости от подкласса, если вы все объекты будете обрабатывать как Base

  Ответить  
 
 автор: oleg_alexeev   (19.03.2007 в 11:53)   письмо автору
 
   для: alex19921992   (19.03.2007 в 11:19)
 

>> Так что же значит слово virtual?

Это ключевое слово означает, что данная функция вызывается не непосредственно, а через
указатель, который находится внутри объекта. Когда функция Create создает объект типа Derived1
оператором new, то он помещает в объект указатель на ~Derived1 (для Derived2 - соответственно
на ~Derived2). После использования объектов мы их удаляем оператором delete. Он считывает из
объекта указатель на деструктор и вызывает именно тот деструктор, который соответствует типу
объекта (~Derived1 или ~Derived2).


Base *pobj = Base::Create();
pobj->Draw();  // нарисуется нужная фигура (если Draw виртуальная функция)
delete pobj;  // здесь вызовется именно нужный деструктор


Такой прием программирования называется полиморфизмом (изменение поведения в
производном классе)

>> Вот я знаю, что конструктор инициализирует объект, т.е. дает начальные значения переменным,
>> ну и если объект динамический, то выделяет память под него. А деструктор? Только удалить
>> память и перенаправить указатели в очереди?

Деструктор только освобождает занятые объектом ресурсы, такие как выделенная память (когда
в объекте есть указатели и память выделяется при вызове конструктора или где-то в процессе
работы), дескрипторы файлов, сокетов и т.п.

Если объект входит в какие-либо списки или очереди, то изменение указателей в них - это не
задача деструктора, а задача функции удаления элемента из этой структуры данных.

  Ответить  
 
 автор: alex19921992   (19.03.2007 в 14:05)   письмо автору
 
   для: oleg_alexeev   (19.03.2007 в 11:53)
 

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

  Ответить  
 
 автор: oleg_alexeev   (19.03.2007 в 14:26)   письмо автору
 
   для: alex19921992   (19.03.2007 в 14:05)
 

Нет, не надо. Более того - нельзя самому вызывать деструктор объекта. Вызов конструктора и
деструктора генерируется компилятором автоматически при объявлении объекта на стеке или
при создании и удалении его в глобальной памяти операторами new и delete.

На начальном этапе обучения можно запомнить это в качестве правила - нельзя самому вызывать
конструктор и деструктор.

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

  Ответить  
 
 автор: alex19921992   (19.03.2007 в 15:48)   письмо автору
 
   для: oleg_alexeev   (19.03.2007 в 14:26)
 

То есть я могу сделать конструктор и деструктор пустыми и заботиться обо всем сам?

  Ответить  
 
 автор: oleg_alexeev   (19.03.2007 в 16:18)   письмо автору
 
   для: alex19921992   (19.03.2007 в 15:48)
 

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

  Ответить  
 
 автор: -=Art=-   (23.03.2007 в 21:49)   письмо автору
 
   для: oleg_alexeev   (19.03.2007 в 16:18)
 

>На начальном этапе обучения можно запомнить это в качестве правила - нельзя самому вызывать
>конструктор и деструктор.
Нужно вызывать конструктор явно,хотя бы для того чтобы потом не делать кучу вызовов типа
Obj->SetParamXXX();

  Ответить  
Rambler's Top100
вверх

Rambler's Top100 Яндекс.Метрика Яндекс цитирования