Модераторы: Poseidon
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> [C++] Структура, хранящая обьекты разных типов 
:(
    Опции темы
AlterMann
Дата 23.12.2006, 18:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 35
Регистрация: 25.10.2006

Репутация: нет
Всего: нет



Здравствуйте, товарищи! (:

В общем объясняю проблему.
Есть абстрактный класс продукт, который наследуют ещё 4 класса (подтипы продуктов)...
Я сделал следующим образом: написал 2 конструктора у класса продукт. Один конструктор - спрашивает у пользователя параметры продукта, другой конструктор (полиморфизм) получает эти данные через сигнатуру (если так можно выразиться (: )...

Нужно организовать сохранение объектов подтипов продуктов, в отдельный массив (структуру)... Так вот, я никак не могу придумать как это лучше сделать... По идее, когда объявляешь массив об]ектов подтипов продуктов, то ругается, что неможет найти дефолтовый конструктор, для инициализации элементов массива...
Есть другой, очень красивый способ - создание структуры:
Код

class ProdList
{
 private:
  static ProdList *last;
  ProdList *next;

 public:
  static ProdList *begin;
  Product *Prod;

  ProdList(Product *);
  static void ShowAll();
};
ProdList *ProdList::begin = NULL;
ProdList *ProdList::last = NULL;

ProdList::ProdList(Product *p)
{
  if(begin == NULL) begin = this;
  else last->next = this;
  Prod = p;
  next = NULL;
  last = this;
}

void ProdList::ShowAll()
{
  ProdList *pp = begin;
  while(pp != NULL)
  {
    pp->Prod->Show(); // Show() - виртуальная функция у класса продукт
    pp = next->next;
  }
}

// и дальнейшее добавление объектов в такую структуру следующим образом:
PodProduct MyProduct(...); // создаёшь объект
ProdList AllProd(MyProduct); // запихиваешь объект в структуру

Но! Возникает такая некрасивая штука: Объект создаёшь в одной функции, потом передаёшь указатель на него в другую, где уже происходит тот самый ProdList AllProd(MyProduct);. Но после того как указатель (не тот, который *, а который перемещается по коду программы, обеспечивая её работу) выходит за пределы фунции, в которой создаётся обект класса подпродукт - объект уничтожается (область видимости переменной решает)... и получается, что указатель в структуре ProdList, указывает на область памяти, где уже нет объекта...

Можно сделать другую структуру, для сохранения, которая будет хранить не указатели на объекты, а сами объекты:
Код

template <class P> struct List
{
  P Prod;
  List *next;

};

List <PodProductT1> *begin1 = NULL, *last1 = NULL, *list1;
List <PodProductT2> *begin2 = NULL, *last2 = NULL, *list2;
List <PodProductT3> *begin3 = NULL, *last3 = NULL, *list3;
List <PodProductT4> *begin4 = NULL, *last4 = NULL, *list4;

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

AddProduct(Product *p)
{
  if(p->GetClass() == PodProuctT1T) // GetClass() - метод подпродукта, который возвращает какого типа подпродукт... с буквой Т на конце... (PodProuctT1T)
  {
    last1 = new(List <PodProductT1>);
    last1.Prod = p; // в классе продукт описан operator =
    last1->next = NULL;

    if(begin1 == NULL) begin1 = last1;
    else
    {
      list1 = begin1;
      while(list1->next) list1 = list1->next;
      list1->next = last1;
    }
  }
}

Ругается на пятую строчку, что: "компилятор не может сгенирировать дефолтовый конструктор для класса 'List<PodProductT1>'"

Хожу заморачиваюсь этой проблемой уже недели две... А всё никак не могу придумать как же это всё сохранить...

Наверняка многие уже сталкивались с такой проблемой и решили её для себя... не подскажите, что мне делать?..

ЗЫ Компилятор (Turbo C++ IDE), надо уже прогу сдавать... блин! ):
(:

Это сообщение отредактировал(а) AlterMann - 23.12.2006, 18:20
PM MAIL WWW   Вверх
Rockie
Дата 23.12.2006, 18:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1143
Регистрация: 23.4.2006

Репутация: 13
Всего: 31



Цитата(AlterMann @  23.12.2006,  18:14 Найти цитируемый пост)
Нужно организовать сохранение объектов подтипов продуктов, в отдельный массив (структуру)... Так вот, я никак не могу придумать как это лучше сделать... По идее, когда объявляешь массив об]ектов подтипов продуктов, то ругается, что неможет найти дефолтовый конструктор, для инициализации элементов массива...


AlterMann, если есть базовый класс Base и его потомки Derived1 и Derived2, то можно создать массив указателей на базовый класс, а потом создавать объеты потомков. 
Код
Base* ptrArray[5];
ptrArray[0] = new pDerived1;
ptrArray[1] = new pDerived2;
// и так далее









--------------------
Чтобы иметь большой гардероб - надо иметь большой гардероб.
PM   Вверх
jnb
Дата 23.12.2006, 18:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 29
Регистрация: 4.10.2006

Репутация: 1
Всего: 1



Если у тебя проблема только в сохранении разнотипных объектов, имеющих одного предка, в каком-то массиве (векторе, списке), то можешь поступить следующим образом:
1. объявить массив указателей на свой абстрактный родитель
2. создавать объект не на стеке а в куче, через new: таким образом получаешь указатель на конретный объект
3. в массив добавляешь указатель на этот объект
...
4.  когда массив становиться  не нужен - удаляешь все указатели в нем оператором delete.


Код


//абстрактный класс
class Product 
{
//....
}

// конкретный класс
class Product1: public Product
{
//...
}

...

std::vector<Product*> products;

Product1* pProduct = new Product1();
products.push_back(pProduct);

// тут работаешь со своим массивом продуков через интерфейс абстрактного класса

// тут удаляешь указатели
for(int i = 0; i < products.size(); ++i)
{
   delete products[i];
}



PM MAIL   Вверх
Rockie
Дата 23.12.2006, 19:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1143
Регистрация: 23.4.2006

Репутация: 13
Всего: 31



Цитата(jnb @  23.12.2006,  18:56 Найти цитируемый пост)
2. создавать объект не на стеке а в куче, через new: таким образом получаешь указатель на конретный объект

jnb, на стеке тожде можно, если вытащить ссылку:
Код
    Base *ptrArray[4];
    Derived1 obj1;
    ptrArray[0] = &obj1;


AlterMann, конструкторы базового класса нужно явно вызывать в потомках, вот, сделал пример:

Код
#include "stdafx.h"

#include <iostream>

using std::cout;
using std::string;
using std::endl;

class Base
{
public:
    string productName;
    Base(string name = "default") {productName = name;}
    virtual void f()=0;    // pure virtual, declaration
};


class Derived1: public Base
{
public:
    Derived1(): Base() { };
    // realisation 
    virtual void f() { cout<<"Derived1 "<<productName.c_str()<<endl; };
};


class Derived2: public Base
{
public:
    Derived2(): Base("NamedProduct") { };
    // realisation 
    virtual void f() { cout<<"Derived2 "<<productName.c_str()<<endl; };
};


int main ()
{
    Base *ptrArray[4];
    
    ptrArray[0] = new Derived1();
    ptrArray[1] = new Derived2();
    
    for(int i=0; i<2; i++)
      ptrArray[i]->f();

    return 0;
}





--------------------
Чтобы иметь большой гардероб - надо иметь большой гардероб.
PM   Вверх
jnb
Дата 23.12.2006, 20:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 29
Регистрация: 4.10.2006

Репутация: 1
Всего: 1



Цитата(Rockie @ 23.12.2006,  19:41)
jnb, на стеке тожде можно, если вытащить ссылку:
Код
    Base *ptrArray[4];
    Derived1 obj1;
    ptrArray[0] = &obj1;


без сомнения можно и на стеке, но как мне показалось AlterMann жаловался именно на разрушение объекта: т.е. массив переживает объекты на которые ссылаются его элементы.
PM MAIL   Вверх
AlterMann
Дата 24.12.2006, 01:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 35
Регистрация: 25.10.2006

Репутация: нет
Всего: нет



Спасибо большое! очень помогли...  smile 
Сильно загнался по поводу связных списков... и запутался...  smile 
Таки распутали вы меня!  smile 

Это сообщение отредактировал(а) AlterMann - 24.12.2006, 02:00
PM MAIL WWW   Вверх
AlterMann
Дата 24.12.2006, 19:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 35
Регистрация: 25.10.2006

Репутация: нет
Всего: нет



Скажите, а могу ли я прописать в потомке класса продукт
Код

operator += (Product *); // с дальнейшим описанием данного оператора...


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

AddProduct(Product *p)
{
  ...
  ProductList[i] += p;
  ...
}

то не катит, ругается следующим образом:
Код

Invalid pointer addition


Подскажите пожалуйста, где я не прав.
PM MAIL WWW   Вверх
jnb
Дата 24.12.2006, 20:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 29
Регистрация: 4.10.2006

Репутация: 1
Всего: 1



AlterMann напиши, что  конкретно ты хочешь сделать: зачем к одному продукту прибавлять другой? Какого типа у тебя ProductList? Что должна выполнить по твоей задумке инструкция  ProductList[i] += p;?
А то в моем понимании твой operator+= выполняет добавление к кефиру скажем батона или селедки...
PM MAIL   Вверх
AlterMann
Дата 24.12.2006, 22:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 35
Регистрация: 25.10.2006

Репутация: нет
Всего: нет



jnb, начну по порядку:
ProductList - у меня - массив указателей на объекты подпродуктов (наследников абстрактного класса Product). Вы же мне про этот массив и написали... (:

При добавлении продукта проверяется, есть ли уже такой продукт:
Код

void AddProduct(Product *p)
{
  int i;

  for(i=0;i<Nums;i++)
  {
    if(ProductList[i] == p)
    {
      ProductList[i] += p;
      break;
    }
  }
// ...
}

(т.е. по идее мне ещё нужно переопределить оператор ==, вернее я его переопределил, но ситуация такая же как и с +=)
И если продукт уже есть (по разным параметрам проверяет, типа дата производства, каллорийность), то просто прибавляем новый продукт к уже существующему...

Это сообщение отредактировал(а) AlterMann - 24.12.2006, 22:30
PM MAIL WWW   Вверх
AlterMann
Дата 25.12.2006, 04:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 35
Регистрация: 25.10.2006

Репутация: нет
Всего: нет



Извините... спасибо... сделал уже...
Нужно ж обращаться по указателю
Код

ProductList[i]->operator == (p);

PM MAIL WWW   Вверх
Rockie
Дата 25.12.2006, 15:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1143
Регистрация: 23.4.2006

Репутация: 13
Всего: 31



Цитата(AlterMann @  24.12.2006,  22:27 Найти цитируемый пост)
И если продукт уже есть (по разным параметрам проверяет, типа дата производства, каллорийность), то просто прибавляем новый продукт к уже существующему...

А зачем?.. Нельзя просто счетчик продуктов где-то завести?


--------------------
Чтобы иметь большой гардероб - надо иметь большой гардероб.
PM   Вверх
jnb
Дата 25.12.2006, 21:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 29
Регистрация: 4.10.2006

Репутация: 1
Всего: 1



вот так тоже должно работать:

Код

(*ProductList[i]) == p
(*ProductList[i]) += p



PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Центр помощи"

ВНИМАНИЕ! Прежде чем создавать темы, или писать сообщения в данный раздел, ознакомьтесь, пожалуйста, с Правилами форума и конкретно этого раздела.
Несоблюдение правил может повлечь за собой самые строгие меры от закрытия/удаления темы до бана пользователя!


  • Название темы должно отражать её суть! (Не следует добавлять туда слова "помогите", "срочно" и т.п.)
  • При создании темы, первым делом в квадратных скобках укажите область, из которой исходит вопрос (язык, дисциплина, диплом). Пример: [C++].
  • В названии темы не нужно указывать происхождение задачи (например "школьная задача", "задача из учебника" и т.п.), не нужно указывать ее сложность ("простая задача", "легкий вопрос" и т.п.). Все это можно писать в тексте самой задачи.
  • Если Вы ошиблись при вводе названия темы, отправьте письмо любому из модераторов раздела (через личные сообщения или report).
  • Для подсветки кода пользуйтесь тегами [code][/code] (выделяйте код и нажимаете на кнопку "Код"). Не забывайте выбирать при этом соответствующий язык.
  • Помните: один топик - один вопрос!
  • В данном разделе запрещено поднимать темы, т.е. при отсутствии ответов на Ваш вопрос добавлять новые ответы к теме, тем самым поднимая тему на верх списка.
  • Если вы хотите, чтобы вашу проблему решили при помощи определенного алгоритма, то не забудьте описать его!
  • Если вопрос решён, то воспользуйтесь ссылкой "Пометить как решённый", которая находится под кнопками создания темы или специальным флажком при ответе.

Более подробно с правилами данного раздела Вы можете ознакомится в этой теме.

Если Вам помогли и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, Poseidon, Rodman

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Центр помощи | Следующая тема »


 




[ Время генерации скрипта: 0.1588 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.