Студопедия.Орг Главная | Случайная страница | Контакты | Мы поможем в написании вашей работы!  
 

Модульне програмування



Набір зв'язаних процедур разом з даними, які вони обробляють, називається модулем. Модуль – програмний фрагмент, який є будівельним блоком для побудови великих програм. Як правило, модуль складається з інтерфейсної частини та частини реалізації.

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

При розв'язанні задач, для яких не потрібне розділення даних на декілька частин і групування цих даних разом з функціями, що їх обробляють, достатньо процедурного стилю програмування.

Оскільки оброблювані дані – тільки частина того, що хочеться приховати усередині модуля, принцип приховування даних тривіальним чином розширюється до принципу приховування інформації в модулях, який полягає в тому, що імена змінних, констант, функцій та типів також можуть бути зроблені локальними в модулі.

Фактично робота будь-якої програми зводиться до отримання, зберігання, модифікації і видачі назовні якихось даних. В програмах дані оголошуються, обробляються і зберігаються в формі безпосередньо заданих значень (літералів) та різного роду змінних, структур і об'єктів, які ідентифікуються в програмах своїми іменами. Для локалізації цих даних в окремих частинах програми, включаючи модулі, в мові C++ є спеціальний механізм просторів імен. Мова С++ дозволяє помістити будь-яке оголошення в простір імен.

5.1 Простори імен

Будь-яка реальна програма складається з деякої кількості окремих частин. Як приклад наведемо просту програму, що видає на екран повідомлення «Добридень, мир!»:

#include <iostream>

using namespace std;

int main(int argc, char *argv[])

{

cout << “ Добридень, мир!”;

return 0;

}

Навіть ця програма складається з двох частин: коду користувача, що вимагає вивести «Добридень, мир!», та модуля вводу – виводу, що підключається до програми директивою #include <iostream> і безпосередньо здійснює вивід повідомлення.

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

Небезпека колізії частіше всього спостерігається для зовнішніх глобальних ідентифікаторів, що використовуються повсюдно в програмі. Ці глобальні імена є видимими для всіх модулів прикладної програми, зовнішніх класів і бібліотек. Якщо два об'єкти в глобальній області видимості мають однакові імена, об’єднувач видасть повідомлення про помилку.

Простори імен дозволяють захистити всі ідентифікатори програми від різноманітних колізій.

5.1.1 Інструкція namespace. Оператор розширення області видимості (::)

Простір імен є механізмом логічного групування. Тобто, якщо деякі оголошення можна об'єднати за якимось критерієм, їх треба помістити в один простір імен.

Члени простору імен оголошуються за допомогою інструкції namespace:

namespace namespace_name

{

// послідовність оголошень та визначень

}

Все, що оголошене всередині блоку однієї інструкції namespace, знаходиться усередині області видимості простору імен із заданим ім'ям.

Наприклад:

namespace MyNameSpace

{

int i, k;

void myfunc(int j){cout << j;}

class myclass

{

int i;

public:

void seti(int x){i = x;}

int geti() {return i;}

};

}

Тут імена змінних i та k, функціяmyfunc(), а також клас myclass знаходяться в області видимості, визначеній простором імен MyNameSpace.

До імен, оголошених в просторі імен, всередині цього простору можна звертатися безпосередньо, указуючи тільки ідентифікатор. Наприклад, в просторі імен MyNameSpace в інструкції return i; змінна i задана без вказівки простору імен.

Проте при зверненні ззовні простору імен до об'єктів, оголошених всередині цього простору, потрібно використовувати оператор розширення області видимості (::):

namespace_name::member

Наприклад, щоб присвоїти значення 10 змінній i в тій частині програми, яка не входить до простору імен MyNameSpace, потрібно використати наступну конструкцію:

MyNameSpace::i = 10;

Є можливість оголосити в програмі більше ніж один простір імен з тим же ім'ям. Це дозволяє розділяти простір імен одного модуля на декілька файлів або навіть розділити простір імен всередині одного модуля.

Як приклад модуля розглянемо програму, що містить оголошення інтерфейсу і реалізацію стека символів.

При проектуванні зазначеного модуля хотілося б забезпечити наступне:

- надати інтерфейс користувача для стека (наприклад, функції push() і pop(), які поміщають та дістають дані зі стека);

- гарантувати, що представлення даних стека, наприклад, у вигляді масиву елементів, доступне тільки через цей інтерфейс користувача;

- виконати ініціалізацію даних стека до його першого використання.

Як варіант, інтерфейс користувача модуля stack може бути оголошений і використаний так:

namespace stack

{

void push(char);

char pop();

}

void f()

{

stack:: push(‘c’);

if (stack:: pop()!= ‘c’) error(“Таке неможливо!”);

}

Оператор розширення області видимості stack:: в реалізації функції f() означає, що імена функцій pop() і push() беруться з простору імен stack. Використання таких же імен в іншому місці не приведе до плутанини.

Визначення (реалізація алгоритмів) стека може бути зроблено в окремо компільованій частині програми:

namespace stack

{

const int max_size = 200;

char v[max_size];

int top = 0;

void push(char c)

{

// перевірити на переповнення стека і помістити в стек

}

char pop()

{

// перевірити, чи не порожній стек, і дістати символ із стека

}

}

Ключовим тут є те, що інтерфейс користувача відокремлений від способу представлення даних і алгоритмів реалізації функцій stack::push() і stack::pop().

5.1.2 Інструкція using

Якщо в програмі звернення до об'єктів якогось простору імен здійснюються досить часто, можна уникнути громіздкої вказівки простору імен з оператором розширення області видимості. Для цього служить інструкція using, дві форми використання якої наступні:

using namespace namespace_name;

using namespace_name::member;

У першій формі інструкції аргумент namespace_name задає ім'я простору імен, доступ до якого потрібно одержати. При використанні цієї форми інструкції using всі члени, оголошені у вказаному просторі імен, стають доступними в поточному просторі імен і з ними можна працювати безпосередньо, без необхідності кожного разу вказувати ім'я простору і оператор розширення області видимості. Наприклад:

using namespace std;

Ця інструкція робить доступними прямо всі об'єкти стандартної бібліотеки C++, зокрема, стандартні потоки вводу – виводу cin, cout і cerr. Без використання цієї інструкції їх довелося б задавати як std::cin, std::cout і std::cerr, відповідно.

При використанні другої форми інструкції using в поточному просторі імен робиться видимим тільки вказаний член заданого простору імен. Наприклад, якщо є описаний вище простір імен MyNameSpace, тоді будуть правильні всі представлені нижче інструкції:

// друга форма інструкції using

using MyNameSpace::k; // видимою робиться тільки змінна k

k = 10;

// перша форма інструкції using

using namespace MyNameSpace; // видимими робляться всі члени

// простору імен

i = 10;

5.2 Роздільна компіляція

С++ включає засоби роздільної компіляції модулів. Так, інтерфейс програми stack, текст якого був приведений раніше, поміщається в окремий заголовний файл з розширенням.h, в даному випадку файл з ім'ям stack.h.

Користувачі, що використовують стек і, можливо, інтерфейси інших програм, повинні включити їх заголовні файли в свої програми за допомогою директиви препроцесора #include:

#include “stack.h”

void f()

{

// …

}

Фрагменти програм, що містять виконавчі інструкції, поміщаються у файли реалізації з розширенням.c (для програм на мові C) або.cpp (для програм на мові C++). Код програми, наведеної вище, можна помістити, наприклад, у файл user.cpp.

Програма, що реалізує алгоритми інтерфейсу stack, також повинна містити в собі інструкцію включення заголовного файлу з інтерфейсом:

#include “stack.h”

namespace stack

{

// …

}

Інструкції цієї програми повинні бути поміщені у файл з ім'ям stack.cpp.

Графічно згадані фрагменти програми та їх зв'язки можна представити таким чином:

 
 

Малюнок 5.1 Зв'язки між роздільно компільованими частинами програми

Роздільна компіляція грає серйозну роль у всіх реальних програмах, хоча, строго кажучи, вона не є елементом мови, а відноситься до її реалізації.

5.2.1 Директива #include

Директива препроцесора #include наказує компілятору помістити на її місце текстовий файл, ім'я якого задається аргументом директиви. Весь вміст заданого в директиві файлу включається в текст початкового тексту програми замість рядка з директивою. Включення багаторівневе - якщо файл, що включається, містить свої директиви #include, всі вони замінюються на тексти відповідних файлів, і т. д.

Синтаксис використання директиви один з наступних:

#include “header_name”

#include <header_name>

В якості аргументу header_name інструкції має бути задано ім'я файлу з розширенням.h (або.hpp) або, відповідно до стандарту на мову C++, ідентифікатор заголовка, по якому компілятор знайде необхідний файл.

Якщо у складі імені заголовного файлу заданий шлях до файлу, компілятор, використовуючи вказаний шлях, знаходить файл, відкриває його і включає вміст файлу замість директиви #include.

Якщо шлях до файлу не заданий, а задано тільки просте ім'я файлу з розширенням, тоді перша і друга форма синтаксису розрізняються алгоритмом пошуку заголовного файлу по довідниках файлів.

Форма з аргументом “header_name”, в якій ім'я заголовного файлу задається в подвійних лапках, змушує компілятор шукати заголовний файл спочатку в довіднику поточного файлу, тобто файлу, який містить директиву #include, потім в довідниках файлів по ієрархії, які включають (#include) поточний файл. Якщо заголовний файл у вказаних довідниках не був знайдений, файл шукається в довіднику \include компілятора (для Visual C++ 7.1 – це довідник “диск:\Program Files\Microsoft Visual Studio.NET 2003\Vc7\include”). Як тільки заголовний файл знайдений, його вміст заміщає директиву #include.

Наприклад:

#include “defs.h”

Форма <header_name>, в якій ім'я заголовного файлу задається в кутових| дужках, має на увазі, що треба включити в програму бібліотечний заголовний файл, і примушує компілятор шукати файл відразу в довіднику \include компілятора (довідник “диск:\Program Files\Microsoft Visual Studio.NET 2003\Vc7\include” для Visual C++ 7.1). Якщо заголовний файл знайдений, його вміст поміщається замість директиви #include.

Наприклад:

#include <stdio.h>

Відповідно до стандарту на мову C++ в директиві #include в кутових |дужках замість імені реально існуючих бібліотечних заголовних файлів потрібно задавати стандартні ідентифікатори, по яких компілятор знаходить необхідні файли. Нові заголовки є абстракціями, що гарантують оголошення потрібних в програмах прототипів і визначень мови Standard C++. Оскільки нові заголовки не є іменами файлів, їх потрібно задавати в кутових| дужках без розширення.h або.cpp. Нижче представлені приклади таких заголовків:

#include <iostream>

#include <fstream>

#include <vector>

#include <string>

6 МАКРОЗАСОБИ. ПРОГРАМУВАННЯ НА АСЕМБЛЕРІ

У мові системного програмування важко, якщо взагалі можливо, обійтися без макрозасобів – засобів програмування за допомогою макросів. Макроси включаються в програму за допомогою особливих конструкцій мови - директив, і обробляються спеціальним препроцесором на текстовому рівні перед запуском в роботу компілятора мови C++.





Дата публикования: 2014-11-03; Прочитано: 3036 | Нарушение авторского права страницы | Мы поможем в написании вашей работы!



studopedia.org - Студопедия.Орг - 2014-2024 год. Студопедия не является автором материалов, которые размещены. Но предоставляет возможность бесплатного использования (0.013 с)...