Добавил:
t.me Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

2 семестр / Литература / Язык программирования С++. Краткий курс. Страуструп

.pdf
Скачиваний:
9
Добавлен:
16.07.2023
Размер:
31.34 Mб
Скачать

3 Модульность

-

Не прерывайте меня,

пока я прерываю вас.

+ + + + +

Уинстон Черчилль

Введение Раздельная компиляция

Модули (С++20)

Пространства имен

Обработка ошибок Исключения

+

Инварианты Альтернативные варианты обработки ошибок Контракты Статические проверки

Арrументы и возвращаемые значения функций

Передача аргументов

+

Возврат значения

Структурное связывание Советы

3.1.

Введение

Программа

на

языке

программирования

С++

состоит

из

множества

от­

дельно

разработанных

частей,

таких

как

функции

1.2.1

),

пользовательские

типы

(глава

2,

"Пользовательские

типы"),

иерархии

классов

(§4.5)

и

шаблоны

(глава

6,

"Шаблоны").

Ключом

к

управлению

всеми

этими

частями

является

четкое

определение

взаимодействия

между

ними.

Первым

и

самым

важным

шагом

является

разграничение

интерфейса

части

и

ее

реализации.

На

уров­

не

языка

С++

представляет

интерфейсы

с

помощью

объявлений. Объявление

определяет

все,

что

необходимо

для

использования

функции

или

типа.

На­

пример:

54

Глава 3. Модульность

/ /

Vector. срр:

 

#include "Vector.h"

 

Vector::Vector(int s)

 

 

:elem{new douЬle[s]),

sz{s)

/ /

Интерфейс Vector

//

Определение конструктора

//Инициализация членов

douЬle&

Vector::operator[]

{

 

 

return

elem[i];

(int

i)

//Определение

оператора

индекса

int

Vector::size()

 

return sz;

11

Определение

size()

Код

в

user.

срр

и

Vector.

срр

совместно

использует

информацию

интер­

фейса

Vector,

представленную

в

Vector.

h,

но

в

остальном

эти

два

файла

независимы и могут быть скомпилированы отдельно. Графически программы могут быть представлены следующим образом.

фрагменты

Vector.h:

интерфейс

Vector

user .срр:

 

linclude

"Vector.h"

использует Vector

Vector. срр:

 

linclude

"Vector.h"

определяет Vector

Строго

говоря,

использование раздельной

компиляции

не

является

языко­

вым

вопросом;

это

вопрос

о

том,

как

лучше

всего

использовать

конкретную

реализацию

языка.

Однако

он

имеет

большое

практическое

значение.

Наи­

лучший

подход

к

организации

программы

состоит

в

том,

чтобы

рассматри­

вать

программу

как

набор

модулей

с

точно

определенными

зависимостями,

логически

представить

модульность

с

помощью

языковых

средств,

а

затем

использовать

физическую

модульность

с

помощью

файлов для

эффективной

раздельной компиляции.

Файл. срр, компилируемый

сам

по

себе

(включая

файлы.

h,

которые

он

включает

с

помощью

директивы

iinclude),

именуется

единицей

трансля­

ции.

Программа

может

состоять

из

многих

тысяч

единиц

трансляции.

56

Глава

3. Модульность

Vector::Vector(int s)

 

 

:elem{new

douЬle[s] },

sz{s}

11

Инициализация

членов

douЬle&

Vector::operator[]

1

 

elem[i];

return

(int

i)

int

Vector::size()

return

sz;

export

int

size

(const Vector& v)

{

return

v.

size

();

}

Здесь определен модуль с именем Vector, который экспортирует

Vector, все его функции-члены, а также свободную функцию size ().

класс

Способ

применения

модулей

состоит

в

их

импорте

при

необходимости.

Например:

11

Файл

user.cpp:

import

Vector;

// Получение

#include <cmath>

//Интерфейс

douЫe

sqrt_sum(Vector& v)

1

sum =

 

douЫe

О;

for(int

i=O;

i!=v.size();

sum+=std::sqrt(v[i]);

return

sum;

 

интерфейса Vector

 

 

математических функций,

включая

++i)

 

 

//Сумма квадратных

корней

sqrt()

Я

мог

бы

импортировать

и

математические

функции

стандартной

библио­

теки,

но

я

использовал

старомодный

#include,

чтобы

показать,

что

вы

може­

те

смешивать

старые

и

новые

директивы

в

одной

программе.

Такое

смешение

необходимо

для постепенного

перевода

старого

кода

с

#include

на

import.

Различие

между

заголовочными

файлами

и

модулями

не

просто

синтакси­

ческое.

Модуль компилируется только один раз (а

не

в каждой единице трансля­

ции, в которой он используется).

 

 

 

Два модуля могут импортироваться в любом

порядке без изменения их

смысла.

 

 

 

Если вы импортируете нечто в модуль, то

пользователи этого модуля не

получают неявный доступ к тому, что

вы

импортируете (и импортиро­

ванные сущности никак не влияют на

вашу работу): import не являет­

ся

транзитивным.