Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Контейнеры С++  (Прочитано 9292 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Helen09
Новенький

ru
Offline Offline

« : 03-06-2010 19:52 » 

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

Код:
#include <conio.h>
#include <iostream.h>
 
// Базовый класс student
class student
{
   private:
   char *name;          // Имя студента
   int kurs, id;        // Номер курса и иднетицикационный номер
 
   public:
   student()            // Конструктор по умолчанию (без параметров)
   {
      name = new char[7];        // Выделяем участок памяти под имя (7 символов типа char)
      strcpy(name, "Ivanov");    // Имя по умолчанию - Ivanov
      kurs = 1;
      id = 001;
   }
 
   student(char *nm, int kr, int ident)  // Конструктор с параметрами
   {
      name = new char[strlen(nm+1)];
      strcpy(name, nm);
      kurs = kr;
      id = ident;
   }
 
   ~student()                            // Деструктор
   {
      delete [] name;                    // Освобождаем память
   }
 
   void print()        // Метод печатает информацию на экране
   {
      cout << endl << "Name: " << name << endl;
      cout << "Kypc: " << kurs << endl;
      cout << "ID  : " << id << endl << "-------------" << endl;
   }
};
 
 
 
// Производный класс student_1
class student_1 : public student
{
   private:
   char* tema;             // Поле под название темы
 
   public:
   student_1() : student()     // Конструктор по умолчанию (также вызывается конструктор по умолчанию student() базового класса
   {
      tema = new char[22];     // Выделяем память под название темы
      strcpy(tema, "Class and polimorfizm");  // Название темы по умолчанию
   };
 
   // Конструктор с параметрами
   student_1(char* nm, int kr, int ident, char* tem) : student(nm, kr, ident)
   {
      tema = new char[strlen(tem+1)];
      strcpy(tema, tem);
   }
 
   ~student_1()             // Деструктор
   {
      delete [] tema;       // Освобождаем память
   }
 
   void print()           // Переопределяем метод вывода информации на экран
   {
      cout << endl << "TeMa: " << tema;
      student::print();   // Вызываем метод print() базового класса student
   }
int main(int argc, char* argv[])
{
   int kr, ident;
   string nm, tema;
 
   cout << "BBeguTe uM9 :";
   cin >> nm;
   cout << "BBeguTe HoMep Kypca :";
   cin >> kr;
   cout << "BBeguTe ID :";
   cin >> ident;
   cout << "BBeguTe TeMy gunJIoMa :";
   cin >> tema;
 
   student_1 a;             // Создаём объект класса student_1 по умолчанию
   student_1 b(nm.begin(), kr, ident, tema.begin());  // Создаём объект класса student_1 с параметрами
 
   a.print();
   b.print();               // Вызываем методы вывода на экран
 
 
        getch();
        return 0;
}
 
};
Записан
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #1 : 04-06-2010 03:59 » 

Поправил код:
1. не понятно зачем использовать в коде и char * и string для хранения строк, переделал всё на string
2. деструктор не виртуальный, это не сильно хорошо для полиморфного кода
3. конструкторы корявые, переписал на C++ Улыбаюсь
Код:
#include <iostream>

using namespace std;
// Базовый класс student
class student
{
private:
string name; // Имя студента
int kurs; // Номер курса
int id; // Иднетицикационный номер

public:
    student() // Конструктор по умолчанию (без параметров)
: name("Ivanov")
, kurs(1)
, id(1)
    {}

    student(const string & nm, int kr, int ident) // Конструктор с параметрами
: name(nm)
, kurs(kr)
, id(ident)
    {}

    virtual ~student() {}

    void print()        // Метод печатает информацию на экране
    {
        cout << endl << "Name: " << name << endl;
        cout << "Kypc: " << kurs << endl;
        cout << "ID  : " << id << endl << "-------------" << endl;
    }
};

// Производный класс student_1
class student_1 : public student
{
private:
    string tema; // Поле под название темы

public:
    student_1() // Конструктор по умолчанию
: tema("Class and polimorfizm")
    {}

    // Конструктор с параметрами
    student_1(const string & nm, int kr, int ident, const string & tem)
: student(nm, kr, ident)
, tema(tem)
    {}

    virtual ~student_1() {} // Деструктор

    void print()           // Переопределяем метод вывода информации на экран
    {
        cout << endl << "TeMa: " << tema;
        student::print();   // Вызываем метод print() базового класса student
    }
};

int main(int argc, char* argv[])
{
    int kr, ident;
    string nm, tema;

    cout << "BBeguTe uM9 :";
    cin >> nm;
    cout << "BBeguTe HoMep Kypca :";
    cin >> kr;
    cout << "BBeguTe ID :";
    cin >> ident;
    cout << "BBeguTe TeMy gunJIoMa :";
    cin >> tema;

    student_1 a;             // Создаём объект класса student_1 по умолчанию
    student_1 b(nm, kr, ident, tema);  // Создаём объект класса student_1 с параметрами

    a.print();
    b.print();               // Вызываем методы вывода на экран

    getch();
    return 0;
}


Теперь по задаче:
1. Список, что односвязный, что двусвязный обычно не имеет произвольного доступа, т.е. только по очереди перебрать все элементы до нужной позиции
2. Список надо реализовать самим или стандартный подойдёт
3. я бы вместо списка выбрал deque двунаправленная очередь с произвольным доступом
4. загрузка и выгрузка в файл обычно называется сериализацией - вот статья в нашей вики http://wiki.shelek.ru/index.php/FAQ:STL:C%2B%2B_%D1%81%D0%B5%D1%80%D0%B8%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F_%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85
Записан

Странно всё это....
Helen09
Новенький

ru
Offline Offline

« Ответ #2 : 04-06-2010 07:26 » 

Извиняюсь что не указала сразу, проблема в том, что у меня должен быть список из 15-ти студентов. Надо выгрузить эти данные из файла. Вставить информацию в произвольную позицию. Получить указатель  к произвольной позиции. А потом еще и записать  обратно в фаил.
 А в представленном мной кодом, только один студент, и меняется у него только тема диплома.
Записан
Helen09
Новенький

ru
Offline Offline

« Ответ #3 : 04-06-2010 16:54 » 

При реализации двусвязного списка, создаем структуру, в которой будем хранить 3 элемента: указатель на предыдущий элемент, указатель на следующий и самого студента/указатель на него.

Код:
struct SLISTITEM
{
   SLISTITEM* pPrevItem;
   SLISTITEM* pNextItem;
   student_1 s; //или student_1* student;
}
Далее создаёте класс списка
class mylist
{
public:
   ~mylist()
   {
      while (pData) // очищаем список при его удалении
      {
         pCurrent = pData->pNextItem;
         delete pData;
         pData = pCurrent;
      }
   }
   void Insert(const student_1& s)
   {
      SLISTITEM* pItem = new SLISTITEM(); //создаём новый элемент списка
      pItem->s = s; //присваиваем студента

      // устанавливаем связи между элементами
      pItem->pPrevItem = pCurrent;
      if (pCurrent)
      {
         pCurrent->pNextItem = pItem;

         pItem->pNextItem = pCurrent->pNextItem;
         pCurrent->pNextItem->pPrevItem = pItem;
      }
      else
      { pItem->NextItem = NULL; }

      pCurrent = pItem; //делаем созданный элемент текущим

      // если первого элемента списка не существует, то укажем его
      if (!pData)
      { pData = pItem; }
   }
   void Remove()
   {
      if (pCurrent)
      {
         // сохраним указатели на следующий и предыдущий элементы
         SLISTITEM* pPrevItem = pCurrent->pPrevItem;
         SLISTITEM* pNextItem = pCurrent->pNextItem;

         // удаляем текущий
         delete pCurrent;

         // если предыдущий элемент существует, то укажем ему следующий после него
         if (pPrevItem)
         { pPrevItem->pNextItem = pNextItem; }

         // если следующий элемент существует, то укажем ему предыдущий до него и сделаем pNextItem выбранным элемнтом
         if (pNextItem)
         {
            pNextItem->pPrevItem = pPrevItem;
            pCurrent = pNextItem;
         }
         else
         { pCurrent = pPrevItem; } //иначе текущим будет предыдущий
      }
   }
   HRESULT Move(int offset)
   {
      // запоминаем текущий элемент
      SLISTITEM* pItem = pCurrent;

      if (offset < 0) //движене по списку влево, пока это возможно или пока не доберёмся до нужного элемента
      {
         while ((offset) && (pItem))
         {
            pItem = pItem->pPrevItem;
            offset--;
         }
      }
      else if (!offset) // двигаться не надо, поскольку отступ равен 0
      { return S_OK; }
      else // движение вправо
      {
         while ((offset) && (pItem))
         {
            pItem = pItem->pNextItem;
            offset++;
         }
      }

      // если pItem равен 0, то отступ превышает число элементов справа/слева при движении вправо/влево и сообщим об ошибке
      if (!pItem)
      { return E_FAIL; }

      pCurrent = pItem; //сделаем найденный элемент текущим
      return S_OK; //сдвиг успешен
   }
   void GoToFirst() { pCurrent = pData; } //перейти к первому элементу
   student_1& GetCurrent() { return pCurrent; } //текущий элемент
private:
   SLISTITEM* pData = 0;//можно его убрать, но код придётся менять немного
   SLISTITEM* pCurrent = 0;
}
подскажите что делать дальше! и как реализовать работу с файлом
Записан
Вад
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #4 : 04-06-2010 19:56 » 

Я бы объявил структуру SLISTITEM внутри класса mylist, приватно - она всё равно никому снаружи не нужна.

Что касается файлов, то тут можно пойти разными путями.
Например, можно определить операторы потокового ввода-вывода (>> и <<) для класса student_1: тогда можно будет писать напрямую в любой поток (включая файловый), и читать аналогично.
Можно сделать в java-like стиле, определить у student_t методы ToString и Parse, которые будут, соответственно, переводить содержимое объекта в строковое представление и обратно.
Записан
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #5 : 07-06-2010 04:26 » 

Helen09
1. не получил явных ответов на поставленные мной вопросы
2. если пишешь свой контейнер в первый раз, то неплохо перед этим ознакомится с интерфейсом существующих, а не писать совершенно неудобный в реальной жизни интерфейс. http://www.cplusplus.com/reference/stl/list/
3. Похоже вы так и не ознакомились с ранее указанной ссылкой.

Поправил ваш код (ну так слегка, что бы размяться перед работой Улыбаюсь ): реализовал интерфейс близкий к требованиям стандарта (кстати отсутствие конструктора в вашем коде это очень плохая идея)

Код: (C++)
template <typename T>
class mylist
{
public:
    typedef T value_type;
    struct Data
    {
        Data(Data * p, Data * n, const value_type & v)
                        : prev(p)
                        , next(n)
                        , value(v)
                {}
        Data* prev;
        Data* next;
        value_type value;
    };

    struct Iterator
    {
        Iterator(Data * v) : value(v) {}
        Data    * value;

        // prefix form
        Iterator& operator++()
        {
            value = value->next;
            return *this;
        }
        // postfix form
        Iterator operator++(int)
        {
            Iterator it = *this;
            value = value->next;
            return it;
        }
        // prefix form
        Iterator& operator--()
        {
            value = value->prev;
            return *this;
        }
        // postfix form
        Iterator operator--(int)
        {
            Iterator it = *this;
            value = value->prev;
            return it;
        }
        value_type & operator*()
        {
            return value->value;
        }
    };
public:

    mylist()
                : size_(0)
                , first_(NULL)
                , last_(NULL)
    { }
   
    ~mylist()
    {
        while (first_) // очищаем список при его удалении
        {
            Data * d = first_->next;
            delete first_;
            first_ = d;
        }
    }
   
    Iterator Begin()
    {
        return Iterator(first_);
    }

    Iterator End()
    {
        return Iterator(NULL);
    }

        value_type & Front() { return first->value; }
        value_type & Back() { return last->value; }
        size_t Size() { return size_; }
        bool Empty() { return size_ == 0; }

    void PushBack(const value_type & v)
    {
        Data * d = new Data(last_, NULL, v);
                if(last_)
                {
                        last_->next = d;
                        last_ = d;
                }
                else
                {
                        first_ = last_ = d;
                }
        ++size_;
    }

    void PopBack()
    {
        if(last_)
        {
                Data * d = last_;
                last_ = last_->prev;
                last_->next = NULL;
                delete d;
                        --size_;
        }
    }

    void PushFront(const value_type & v)
    {
        Data * d = new Data(NULL, first_, v);
                if(first_)
                {
                        first_->prev = d;
                        first_ = d;
                }
                else
                {
                        first_ = last_ = d;
                }
        ++size_;
    }

    void PopFront()
    {
        if(first_)
        {
                Data * d = first_;
                first_ = first_->next;
                first_->prev = NULL;
                delete d;
                        --size_;
        }
    }

    void Insert(Iterator i)
    {
        Data * value = i->value;
        Data * prev = value->prev;
        Data * next = value->next;
       
        Data * d = new Data(prev, next, value->value);
        if(prev)
                        prev->next = d;
        if(next)
                        next->prev = d;
    }
   
    void Remove(Iterator i)
    {
        Data * value = i->value;
        Data * prev = value->prev;
        Data * next = value->next;
       
        if(prev)
                prev->next = value->next;
                if(next)
                next->prev = value->prev;
                if(value == first_)
                        first_ = next;
                if(value == last_)
                        last_ = prev;
                delete value;
    }

private:
        size_t size_;
        Data * first_;
        Data * last_;
};
« Последнее редактирование: 07-06-2010 05:03 от Антон » Записан

Странно всё это....
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines