Раздел «Язык Си».OOP-Instrumental_3sem1:

Объекты могут состоять ихз других объектов, как уже реализованных ранее (например string, sstream, ifstream, ofstream и др.), так и из тех, которые были описаны нами.

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

Рассмотрим пример задачи. Необходимо написать программу, которая позволяет делать запросы на поиск маршрута путешествия. При этом вычисление маршрута происходит "параллельно" с работой запросов.

Сначала рассмотрим устройство классов, которые описывают города и дороги между ними.

Города и дороги.

Заголовочный файл. goroda.h

#include "timedat.h"

//Структура для записи и чтения
// данных в файл
// описание дороги между городами
struct Path{
   char name1[100]; // первый город
   char name2[100]; // второй город
   int distance;   // расстояние между городами
   time_t timeToEnd; // время в пути
};
// класс дорога объявлен заранее
// так как он используется в классе 
// Goroda
class Doroga;

// Класс для описания города
class Gorod{
// Внутренняя структура для описания дороги от этого города
   struct PathTo{
      int distance; // расстояние до второго города
      Gorod *otherEnd; // ССЫЛКА на второй город
      CTime timeToEnd; // время доезда типа CTime
   };
   string name; // имя города
//массив будет динамическим, то есть память будет выделена 
// позже.
// потом можно будет изменить ее размер.
   PathTo *pathes; 
// количество дорог из города
   int nPath; 
   public:
// конструктор
   Gorod (string );
// Деструктор нужен обязательно.
// Динамическая память должна освобождаться
   ~Gorod();
// Необхожимо получить ссылку на город в конце
// дороги
   void getNewPath(const Path&, Gorod*);
// оператор доступа к дороге номер n
// a[2] - вернет объект типа Doroga из динамического
// массива pathes 
   Doroga operator[](int);
// вернуть количество дорог
   int howMuchPath();
// вернуть имя города   
        string getName();
// о городе
   void about();
};

// Описание дороги
class Doroga{
   int distance; // расстояние
   Gorod *point1, *point2; // ссылки на города в конце
   public:
// конструктор
   Doroga(Gorod*, Gorod *, int);
// получить расстояние
   int getDistance();
// получить ссылку на ДРУГОЙ город
   Gorod* getOtherEnd();
// сравнить две дороги на полное соответствие
   int operator==(const Doroga&);
// сравнить дороги по расстоянию
   int operator>(const Doroga&);
// сравнить дороги по времени доезда
   int operator<(const Doroga&);
// о дороге
   void about();
};

Файл реализации (функции реализованы частично).

#include "goroda.h"
#define MAXGOR 20
// Конструктор
Gorod::Gorod(string nm){
   name = nm;
   pathes = 0;
   nPath = 0;
};
// Деструктор
Gorod::~Gorod()
{
// если память выделена, то она удалаяется
   if(pathes)
// оператор освобождения памяти
// free не использовать!!!!!
      delete[] pathes;
};
// Заполняем информацию о дорогах
void Gorod::getNewPath(const Path& pt, Gorod* gt){
// если дорог еще не было выделяем память.
   if ( ! nPath ){
      pathes = new PathTo[MAXGOR];
   }
// запоминаем ссылку на другой город
   pathes[nPath].otherEnd = gt;

// запоминаем расстояние
   pathes[nPath].distance = pt.distance;

// САМОСТОЯТЕЛЬНО НАПИСАТЬ КОД ДЛЯ ЗАПОЛНЕНИЯ
// ВРЕМЕНИ ДОЕЗДА

   nPath++;
};

// Информация о городе и его дорогах
void Gorod::about(){
   cout<<name<<" - "<<nPath<<endl;
// если есть дорогои  печатаем
   if(nPath){
      for( int i = 0; i < nPath; i++){
         cout<<pathes[i].distance<<" до "<<(pathes[i].otherEnd)->name<<endl;
      }
   }
};

// вернуть имя города
string Gorod::getName(){
   return name;
};

// оператор []
Doroga Gorod::operator[](int n){
// Генерим временный объект Doroga
// первый параметр - указатель на ТЕКУЩИЙ объект
// остальные берем из массива pathes
   Doroga tmp(this, pathes[n].otherEnd, pathes[n].distance);
// возвращаем временный объект
    return tmp;
};

//========================== реализация классса Doroga=================

// Конструктор
Doroga::Doroga(Gorod* a, Gorod* b, int dst){
   point1 = a;
   point2 = b;
   distance = dst;   
};

// информация о дороге
void Doroga::about(){
   cout<<point1->getName()<<"<-" <<distance<<"->"<<point2->getName()<<endl;
}

Тестирование

#include "goroda.h"

int main(){
   Gorod a("Кукуевка"),b("Гадюкино"),c("Обираловка"),d("Шуша");
   a.about();
   b.about();
   Path z={"Кукуевка","Гадюкино",270,864000};
   Path z1={"Кукуевка","Обираловка",340,1296000};
   Path z2={"Кукуевка","Шуша",340,1296000};
   a.getNewPath(z,&b);
   b.getNewPath(z,&a);
   a.getNewPath(z1,&c);
   c.getNewPath(z1,&a);
   a.getNewPath(z2,&d);
   d.getNewPath(z2,&a);
   a.about();
   b.about();
   c.about();
   d.about();
// a[1] веренет объект типа Doroga - элемент 1
// из pathes
// (a[1]) - объект, (a[1]).about() - обращение к 
// функции about() этого объекта
   (a[1]).about();
        return 0;
}

Задача 1.

Реализовать оставшиеся функции. Проверить из работоспособность.

Дочерние процессы.

Каждый процесс может породить свой дочерний процесс. При этом дочерний процесс наследует от родительского все значения переменных, открытые дескрипторы, терминал. Но этот дочерний процесс — совершенно самостоятельный: у него свой pid, своя память и т.д.

Пример использования порожденных процессов.

#include <unistd.h>
#include <iostream>
#include <cstdlib>
#include <sstream>
#include <ctime> // для clock()
#include <fstream>

using namespace std;
int main(){
// строковый поток (можно пользоваться операторами ввода/вывода
  stringstream sp;
// строка
  string st;
  int pid;   // pid текущего процесса
  int  ppid; // pid родительского процесса
// получить время начала работы родительского процесса
  unsigned int start_time =  clock();
//  в цикле получаем запрос для исполнения: w - запись в файл
// r - читать из файла, d -  удалить 
  while(1){
// получаем строку
   cin>>st;
//  если ввели *, то выходим из программы
   if(st == "*") exit(1);

// порождаем детский процесс
// родительский процесс при этом получает pid детского процесса, 
// а в детском pid будет равен 0
// На каждой итерации цикла порождается 
// НОВЫЙ детский процесс
   pid = fork();
// если это детский процесс, выходим из цикла,
// а родитель остается в цикле получать команды
// каждую команду будет обрабатывать свой детский процесс
   if(pid == 0) break;   
  }

//  получаем порождения детского процесса
  unsigned int run_time =  clock();
// генерим имя файла для записи действий
  sp<<"log_"<<getpid();
// открываем файл на ввод
  ofstream fo;
// sp.str() возвращает строку, а c_str() от строки возвращает C-строку (массив символов)
  fo.open((sp.str()).c_str()); 
// записываем информацию в файл
  fo<<"fork pid: "<<getpid()<<" at time: "<< run_time -start_time<<endl;

  if(st == "w"){
    fo<<" пишем\n";
  }
  if(st == "s"){
    fo<<" ищем\n";
  }
  if(st == "d"){
    fo<<" удаляем\n";
  }
  fo.close();
}

Задача 2.

Написать программу, которая в цикле получает команды:

  1. составить маршрут (вводится список городов)
  2. удалить город
  3. добавить город

Получив команду составить маршрут, программа порождает дочерний процесс, который заносит готовый маршрут в файл pathn, n генерится автоматически. -- TatyanaOvsyannikova2011 - 20 Oct 2016