Организация многофайловых проектов 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Организация многофайловых проектов



 

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

Изучение методологии модульной организации кода, применительно к объектно-ориентированному подходу к программированию (ООППр), основано на организации проекта в виде набора исходных файлов. Предполагается выделение заголовочных файлов и файлов реализации для определения кода классов. Все объявления классов выносятся в заголовочные файлы (hpp — файлы), а реализация методов классов, за исключением случаев с шаблонами классов, выносятся в файлы реализации (cpp — файлы). Главный файл проекта, как правило, получает имя main.cpp. В него включаются необходимые заголовочные файлы, и он содержит минимальный объем программного кода. Рассмотрим это на примере задачи создания класса для представления класса Integer. Проект содержит три файла.

 

Заголовочный файл

 

// filename: mylib.h

#pragma once

#ifndef MYLIB_H__

#define MYLIB_H__

 

#include <iostream>

 

namespace mylib { // Объявление пространства имен

class Integer { // Объявление класса

private:

int val;

public:

Integer(int v = 0);

Integer(Integer const& v);

int getVal()const;

void setVal(int v);

friend std::ostream& operator<<(std::ostream&,

   const Integer&);

friend std::istream& operator>>(std::istream&, Integer&);

};

}

#endif // MYLIB_H__

 

Файл реализации методов класса

 

// filename: mylib.cpp

#include "mylib.h"

#include <iostream>

namespace mylib { // Объявление пространства имен

// Реализация методов класса

Integer::Integer(int v):val(v) {}

Integer::Integer(Integer const& v): val(v.val) {}

int Integer::Integer::getVal()const { return val; }

void Integer::setVal(int v) { val = v; }

  // Реализация дружественных методов класса – перегруженных

// операций потокового ввода – вывода объектов класса

std::ostream& operator<<(std::ostream& output,

                      const Integer& v) {

output << v.val;

return output;

}

std::istream& operator>>(std::istream& input, Integer& v) {

input >> v.val;

return input;

}

}

 

Главный файл проекта

 

// filename: main.cpp

#include <iostream>

#include <cstdlib>

#include "mylib.h"

 

using std::cout;

using std::cin;

using std::endl;

 

int main() {

// BEGIN

mylib::Integer num1(1);

cout << num1 << endl;

cout << "New integer: "; cin >> num1;

cout << num1 << endl;

system("pause");

return 0;

} // END

 

 

Агрегативный тип данных

Структура является одним из базовых типов (базовые, встроенные типы данных) для языков С и С ++, она относится к категории агрегативных типов данных и используется для создания типов данных, определяемых пользователем. С точки зрения теории информации, структурой называют некоторый набор данных и связи, наложенные на эти данные. Благодаря имеющимся связям между данными они выделяются из внешней информационной среды. Можно сказать, что структура – это способ организации информации. Структуры позволяют описывать категории физического мира терминами языка программирования и являются базой для создания абстрактных типов данных (ADT – Abstract Data Type)

В С и С ++ структура – это совокупность данных разного типа, собранных под одним именем. Структура состоит из набора полей, каждое из которых является экземпляром одного из базовых типов данных. Поля, определяющие состав структуры, в С ++ называются ее атрибутами. Существует ряд ограничений, накладываемых на типы полей структур: в языке С полями структур не могут быть функции и экземпляры структур того же типа, что и структура, в которой они объявляются, но могут быть указатели на функции и указатели на структурные переменные того же типа. В С ++ атрибутами структур могут быть и функции, но, как и в С, атрибутами не могут быть переменные того же структурного типа.

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

В ряде случаев, экземпляр структуры называется записью. Это связано с тем, что записи, как и экземпляры структурных переменных, тоже содержат в себе наборы информационных полей — атрибуты. Кроме того, структурированная информация используется при работе с базами данных (БД): экземпляр структуры отражается в виде записи, набора полей таблиц БД.

Общий вид объявления структур в С / С ++.

 

struct <Имя_составного_типа> {

<тип_1> <Имя_атрибута_1>;

<тип_2> <Имя_атрибута_2>;

* * * *

<тип_N> <Имя_атрибута_N>;

};

typedef struct <Имя_составного_типа> {

<тип_1> <Имя_атрибута_1>;

<тип_2> <Имя_атрибута_2>;

* * * *

<тип_N> <Имя_атрибута_N>;

 

} <Псевдоним_для_составного_типа>;

 

Объявление структуры является декларацией для компилятора о том, каким образом должна быть организована информация при создании экземпляров структурных переменных, эта декларация не связана с выделением памяти, память выделяется только при объявлении структурных переменных. Рассмотрим следующие примеры.

Объявление структуры для представления точек на плоскости в Декартовой системе координат.

 

struct TPoint2D { /* объявляется структурный тип TPoint2D, */

float x; /* содержащий два поля типа float   */

float y; 

};  /*объявление структуры заканчивается пустым оператором */

 

Объявление структуры, совмещенное с объявлением двух структурных переменных.

 

struct TPoint2D { /* объявляется структурный тип TPoint2D, */

float x; /* содержащий два поля типа float   */

float y; 

} A, B; // Идентификаторы создаваемых структурных переменных

 

Следует обратить внимание на тот факт, что при объявлении структурных переменных в языке С необходимо использовать ключевое слово struct, являющееся частью имени структурного типа, а в С ++ его можно опускать:

 

struct A { int val; }; /* Объявление структурного типа   */

struct A a1; /* Объявление переменной структурного типа

          по правилам ANSI С                   */

struct A a2 = {1}; /* Объявление стректурной переменной,

                  совмещенное с инициализацией */

 

Поэтому в ANSI C целесообразно использовать форму объявления структурного типа, совмещенную с определением псевдонима для типа (typedef).

 

typedef struct TA { int val; } A; /*Объявление псевдонима для пользовательского структурного типа*/

A a; /* Объявление переменной структурного типа */

 

В языке программирования С ++ такая конструкция является избыточной, так как компилятор ведет собственный «реестр» («реестр» - система учета, специальным образом организованная внутренняя БД) пользовательских типов данных, объявленных в проекте, и добавляет необходимую информацию в объявления переменных. Приведем вариант объявления типа А для языка С ++.

 

struct A { int val; }; // Объявление структурного типа*/

A a;              // Объявление переменной структурного типа

 

Для доступа к полям структур используются две операции: доступ по имени (.) и доступ через указатель (->). Рассмотрим следующий пример.

 

typedef struct Point2D { float x; float y;} TPoint2D;

TPoint2D A, B={0F, 0.5F};

TPoint2D* ptr=&A; /* объявление указателя на структуру     */

A.x=1.15F;   /* обращение к полю структуры по имени   */

ptr->y=2.34F; /* обращение к полю структуры через указатель */

 

Механизмы выделения памяти для экземпляров структур в куче такие же, как и для скалярных типов данных.

 

// ANSI C

typedef struct Point3D {float x; float y; float z;} TPoint3D;

TPoint3D* arrayPoint=(TPoint3D*)malloc(sizeof(TPoint3D)*10);

if(arrayPoin==NULL) {

/* обработка ошибок выделения памяти */

}

arrayPoint[0]->x=0F;

arrayPoint[0]->y=0F;

arrayPoint[0]->z=0F;

/*  Какой-то код...         */

free(arrayPoint); /* освобождение памяти в куче */

 

// С++

struct TPoint2D { // объявляется структурный тип TPoint2D,

float x; // содержащий два поля типа float       

float y; 

};  // объявление структуры заканчивается пустым оператором

Tpoint2D *Polygon = new Tpoint2D[20];

// Цикл инициализации элементов массива структур

// Обработка элементов массива структур.

show(Polygon);    // функция для отрисовки полигона на экране

delete[] Polygon; // Освобождение памяти

 

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

 

struct TPolygon2D {

TPoint2D* arr; // указатель на массив точек

size_t numb; // количество точек в полигоне

};

 

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

 

: Студент
ID: Беззнаковое Длинное Целое Фамилия: Строка Имя: Строка Отчество: Строка Дата_рождения: Дата_Тип Институт: Строка Специальность: Строка Группа: Строка Дата_поступления: Дата_Тип Статус: Беззнаковое Байт Оценки: Беззнаковое Байт Таблица

 

Сообветсвующая предложенной схеме структура на языке С ++ может быть представлена следующим образом:

 

struct Student {

uint64_t id;

std::string surName;   // Фамилия

std::string firstName;   // Имя

std::string patronymic;   // Отчество

std::string institute;   // институт/факультет

std::string specialty;   // специальность

std::time_t birthday;   // Дата рождения

std::time_t enrollment;   // Дата зачисления

uint8_t status;      // Статус: академ.отпуск|отчислен и др.

uint8_t *academicPerformance; // указатель на массив оценок

};

 

Данный способ представления информации о студенте не является оптимальным по использованию памяти и обладает определенной избыточностью в отношении полей, предназначенных для представления информации, как о дате рождения, так и о заде зачисления студента в учебное заведение. Кроме того, хранение информации об оценках, без привязке к названию соответствующих предметов, крайне малоинформативно и не практично. Целесообразно разработать структурный тип для представления данных об успеваемости, который должен содержать как минимум два поля: название предмета и полученная оценка.

 

struct TAcademicPperformance {

std::string article; // название учебного курса

unsigned char assessment; // полученная оценка

};

 

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

 

 

struct Student {

uint64_t id;

std::string surName;     // Фамилия

std::string firstName;     // Имя

std::string patronymic;     // Отчество

std::string institute;     // институт/факультет

std::string specialty;     // специальность

char birthday[3];      // Дата рождения в формате ГГ:ММ:ДД

char enrollment[3];    // Дата зачисления в формате ГГ:ММ:ДД

uint8_t status;        // Статус: академ.отпуск|отчислен и др.

TAcademicPerformance* perf; // указатель на массив оценок

};

 

Подобный подход к организации информации лишь на первый взгляд может показаться слишком сложным, на практике же такой подход применяется достаточно широко. В качестве примера рассмотрим стандатный тип, спользуемый для представления даты и времени – std::tm.

 

struct tm {

int tm_sec; // секунды после минут [0,59]

int tm_min; // минуты после часов [0,59]

int tm_hour; // часы после полуночи [0,23]

int tm_mday; // день месяца [1,31]

int tm_mon; // месяц года (январь = 0) [0,11]

int tm_year; // год (1900 год = 0)

int tm_wday; // день недели (вс = 0) [0,6]

int tm_yday; // день года (1 января = 0) [0,365]

int tm_isdst;  

};

 

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

Следующий пример демонтсирует базовый способ получения информации о величине системных даты и времени.

 

#include <iostream>

#include <iomanip>

#include <ctime>

int main() {

  std::time_t t = std::time(NULL);

  std::tm tm = *std::localtime(&t);

  std::cout << "Time right now is " << std::put_time(&tm, "%c %Z")

       << '\n';

return 0;

}

Как видите, структурный подход к программированию, явивишися предшественником объектно-ориентированного подхода, определяет следующую требования к разработке ПО:

1. определение необходимых структрурных типов, адекватных информационной модели программной системы;

2. поиск и разработка алгоритмов для работы с выбранными структурами;

3. разработка функций, реализующих выбранные методы и алгоритмы.

 

Изучение утилиты who

 

 

ЛАБОРАТОРНАЯ РАБОТА №2



Поделиться:


Последнее изменение этой страницы: 2021-06-14; просмотров: 72; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.135.246.193 (0.061 с.)