В предыдущем уроке мы упоминали, что переменные-члены класса обычно делаются закрытыми. Разработчикам, изучающим объектно-ориентированное программирование, часто бывает трудно понять, зачем это нужно. Чтобы ответить на этот вопрос, давайте начнем с аналогии.
В современной жизни у нас есть доступ ко многим электронным устройствам. У вашего телевизора есть пульт дистанционного управления, который можно использовать для включения/выключения телевизора. Вы едете на работу на машине (или скутере). Вы делаете фотографию на свой смартфон.
Все эти три вещи используют общий шаблон: они предоставляют простой интерфейс (кнопка, руль и т.д.), который вы можете использовать для выполнения действия. Однако то, как на самом деле работают эти устройства, от вас скрыто. Когда вы нажимаете кнопку на пульте дистанционного управления, вам не нужно знать, что он делает для связи с телевизором.
Когда вы нажимаете педаль газа в автомобиле, вам не нужно знать, как двигатель внутреннего сгорания заставляет колеса вращаться. Когда вы делаете фотографию, вам не нужно знать, как датчики собирают свет в пиксельное изображение. Такое разделение интерфейса и реализации чрезвычайно полезно, поскольку позволяет нам использовать объекты, не понимая, как они работают. Это значительно упрощает использование этих объектов и увеличивает количество объектов, с которыми мы можем взаимодействовать.
Часть 8. Объектно-ориентированное программирование. Python по книге «Укус Питона»-A Byte of Python
По тем же причинам разделение реализации и интерфейса полезно и в программировании.
Инкапсуляция
В объектно-ориентированном программировании инкапсуляция (также называемая сокрытием информации) – это процесс скрытия деталей о том, как реализован объект, от пользователей этого объекта. Вместо этого пользователи получают доступ к объекту через открытый, общедоступный интерфейс. Таким образом, пользователи могут использовать объект, не понимая, как он реализован.
В C++ мы реализуем инкапсуляцию через спецификаторы доступа. Как правило, все переменные-члены класса делаются закрытыми (скрывая детали реализации), а большинство функций-членов делаются открытыми (открывая интерфейс для пользователя). Хотя требование, чтобы пользователи класса использовали открытый интерфейс, может показаться более обременительным, чем предоставление открытого доступа к переменным-членам напрямую, это на самом деле дает большое количество полезных преимуществ, которые помогают стимулировать повторное использование класса и его поддерживаемость.
Примечание. Слово инкапсуляция также иногда используется для обозначения упаковки данных и функций, которые работают с этими данными. Мы предпочитаем называть это объектно-ориентированным программированием.
Преимущество: инкапсулированные классы проще в использовании и уменьшают сложность ваших программ
При полностью инкапсулированном классе для его использования вам нужно только знать, какие функции-члены открыты, какие аргументы они принимают и какие значения возвращают. Неважно, как этот класс был реализован внутри.
Как стать ХАКЕРОМ с нуля. Даркнет
Например, класс, содержащий список имен, мог быть реализован с использованием динамического массива строк в стиле C, std::array , std::vector , std::map , std::list или одной из многих других структур данных. Чтобы использовать этот класс, вам не нужно знать (или беспокоиться), какую именно структуру данных он использует. Это значительно снижает сложность ваших программ, а также уменьшает количество ошибок. Это ключевое преимущество инкапсуляции.
Все классы стандартной библиотеки C++ инкапсулированы. Представьте себе, насколько сложнее был бы C++, если бы вам нужно было понять, как были реализованы std::string , std::vector или std::cout , чтобы их можно было использовать!
Преимущество: инкапсулированные классы помогают защитить ваши данные и предотвратить неправильное использование
Глобальные переменные опасны тем, что у вас нет строгого контроля над тем, кто имеет доступ к этим глобальным переменным, или как они используются. Классы с открытыми членами страдают от той же проблемы, только в меньшем масштабе.
Например, предположим, что мы пишем строковый класс. Мы могли бы начать так:
class MyString < char *m_string; // здесь мы динамически разместим нашу строку int m_length; // нам нужно отслеживать длину строки >;
Эти две переменные имеют внутреннюю связь: m_length всегда должна быть равна длине строки, содержащейся в m_string (это соединение называется инвариантом). Если бы m_length была открытой, любой мог бы изменить длину строки, не изменяя m_string (или наоборот). Это поставило бы класс в несогласованное состояние, что могло бы вызвать всевозможные странные проблемы. Делая m_length и m_string закрытыми, пользователи вынуждены для работы с этим классом использовать любые доступные открытые функции-члены (а эти функции-члены могут гарантировать, что m_length и m_string всегда устанавливаются правильно).
Опр. Область действия – часть программы, в которой есть доступ к переменной, ей можно пользоваться
Опр. Объявление переменной – это информация об имени и типе переменной, которая используется компилятором при синтаксическом анализе выражений программы.
Опр. Описание переменной – это либо объявление, либо определение, либо инициализация.
Переменная может быть использована в программе только после ее определения или инициализации.
В программах С/С++ допускается произвольное число объявлений переменной, но только одно ее определение. Именованные константы описываются только в форме инициализации. Обобщенная синтаксическая форма описания переменной в программе имеет вид:
Где тип – один из допустимых типов данных. Квалификаторы – это const и volatile – cv-qualifiers, спецификаторы – это спецификаторы хранения extern, static, register, auto, список_переменных – это список из допустимых идентификаторов, разделенный запятыми, возможно с начальными значениями переменных и обязательно для констант.
Синтаксис определения начальных значений имеет две формы:
1-я форма: идентификатор = начальное_значение;
2-я форма: идентификатор (начальное_значение);
Примеры объявление переменных:
volatile extern long double b;
Примеры определений целочисленных переменных:
unsigned char code;
unsigned lоng long_number;
Примеры определений вещественных переменных:
float x, X, cc3, pot_8;
double e, Stop, B4;
static int I;// По умолчанию = 0;
extern static int j;// По умолчанию = 0;
const volatile char* port = (const volatile char*) 0x30;
const int A(1); // const int A = 1;
Все приведенные примеры являются примерами описания переменных в программе.
1.4.3 Область действия, область видимости, время жизни
переменных
Объявление переменной, кроме типа, класса памяти явно или по умолчанию задает области действия, видимости и время жизни.
По области действия различают локальные и глобальные переменные.
Локальность переменной зависит от места ее определения:
— если переменная определена вне всех блоков программы она будет ГЛОБАЛЬНОЙ, причем область действия будет от точки объявления переменной до конца программы, включая все блоки с их вложениями;
— если переменная определена в блоке, то она будет ЛОКАЛЬНОЙ, причем область ее действия будет от точки объявления переменной до конца блока, включая вложенные блоки.
Время жизни глобальной переменной – время работы программы, время жизни локальной переменной – время активности блока ее определения.
Область действия совпадает с областью видимости, за исключением случая, когда определяется локальная переменная с таким же именем. Говорят, что она маскирует глобальную переменную, исключая блок из области видимости глобальной переменной. Замечание имеет силу и для локальных переменных вложенных блоков, которые тоже могут маскировать переменные внешних блоков.
1.4.4 Статические глобальные и локальные переменные
Если глобальная переменная определяется как статическая, то область ее действия в многофайловых программах сужается до файла ее определения.
Если локальная переменная определяется как статическая, то область ее действия не изменяется, но, во-первых, она по умолчанию инициализируется нулевым значением, во-вторых, время ее жизни становится глобальным.
a=1; // вложенный блок – видна локальная переменная
// видна глобальная переменная
extern int a,b; // Глобальные переменные – объявление
int a=10, b=20; // Глобальные переменные – определение
1.4.5 Спецификатор extern. Внешние переменные
Спецификатор extern играет важную роль в программах, состоящих из нескольких файлов. Программу можно разделить на несколько файлов, выполнить их раздельную компиляцию, а затем отредактировать связи между ними. Для этого нужно сообщить всем файлам программы о глобальных переменных. Лучше всего определить все глобальные переменные в одном файле, а в других объявить их с помощью спецификатора extern. На практике объявление внешних переменных хранят в заголовочных файлах, которые подключаются ко всем файлам программы.
Первый файл – file1.cpp
Второй файл – file2.cpp
Заголовочный файл объявления глобальных переменных myglobal.h:
Первый файл – file1.cpp
#include “myglobal.h” // Не обязательно
Второй файл – file2.cpp
#include “myglobal.h” // Обязательно
Ø Предельные значения типов С.
Предельные значения констант (и соответствующих переменных) разработчики компиляторов вправе выбирать самостоятельно исходя из аппаратных возможностей компьютера. Однако при такой свободе выбора стандарт языка требует, чтобы для значений типа short и int было отведено не менее 16 бит, для lоng — не менее 32 бит. При этом размер lоng должен быть не менее размера int, а int – не менее short. Предельные значения арифметических констант и переменных для большинства компиляторов, реализованных на IBM PC, приведены в таблице
тип данных | размер, бит | диапазон значений |
unsigned char | 0. 255 | |
char | -128. 127 | |
enum | -32768. 32767 | |
unsigned int | 0 — 65535 | |
short int (short) | -32768. 32767 | |
uпsigned short | 0. 65535 | |
int | -32768. 32767 | |
unsigned lоng | 0. 4294967295 | |
lоng | -2147483648. 2147483647 | |
float | 3.4E-38. 3.4E+38 | |
double | 1.7Е-308. 1.7E+308 | |
long double | 3.4E-4932. 1.1E+4932 |
Ø Именованные константы
В языке Cи, кроме переменных, могут быть определены константы, имеющие фиксированные названия (имена). В качестве имен констант используются произвольно выбираемые программистом идентификаторы, не совпадающие с ключевыми словами и с другими именами объектов. Традиционно принято, что для обозначений констант выбирают идентификаторы из прописных букв латинского алфавита и символов подчеркивания.
Первая возможность определения именованных констант — это перечисляемые константы, вводимые с использованием служебного слова enum.
Вторую возможность вводить именованные константы обеспечивают определения такого вида:
const mun uмя_кoнcmcmmы=знaчeнue_кoнcmaнmы;
cоnst double E=2.718282;
cоnst lоng M=99999999;
В последнем определении тип константы не указан, по умолчанию ей приписывается тип int.
Третью возможность вводить именованные константы обеспечивает препроцессорная директива
#define имя_константы значение_константы
Обратите внимание на отсутствие символа «точка с запятой» в конце директивы. В конкретные реализации компиляторов с помощью директив #define включают целый набор именованных констант с фиксированными именами.
Отличие определения именованной константы
cоnst double E=2.718282;
от определения препроцессорной константы с таким же значением:
#define EULER 2.718282 состоит внешне в том, что в определении константы E явно задается ее тип, а при препроцессорном определении константы EULER ее тип определяется «внешним видом» значения константы. Например, следующее определение
вводит обозначение NEXT для символьной константы ‘Z’. Это соответствует такому определению:
const char NEXT = ‘Z’;
Однако различия между обычной именованной константой и препроцессорной константой, вводимой директивой #define, гораздо глубже и принципиальнее. До начала компиляции текст программы на языке Cи обрабатывается специальным компонентом транслятора – препроцессором. если в тексте встречается директива
#define EULER 2.718282
а ниже ее в тексте используется имя константы EULER, Например, в таком виде:
double mix = EULER;
то препроцессор заменит каждое обозначение EULER на ее значение и сформирует такой текст:
double шix = 2.718282;
Далее текст от препроцессора поступает к компилятору. Константы, определяемые на препроцессорном уровне с помощью директивы #define, очень часто используются для задания размеров массивов.
Итак, основное отличие констант, определяемых препроцессорными директивами #define, состоит в том, что эти константы вводятся в текст программы до этапа ее компиляции. Специальный компонент транслятора — препроцессор обрабатывает исходный текст программы, подготовленный программистом, и делает в этом тексте замены и подстановки.
1.5 Принципы работы препроцессора.
Его основное отличие от других компонентов транслятора — обработка программы выполняется только на уровне ее текста. На входе препроцессора — текст с препроцессорными директивами, на выходе препроцессора — модифицированный текст без препроцессорных директив. В связи с именованными константами здесь рассматривается только одна из возможностей директивы #define -простая подстановка.
Подстановка не выполняется в комментариях и в строковых литералах.
Именно с помощью набора именованных препроцессорных констант стандарт языка Cи рекомендует авторам компиляторов определять предельные значения всех основных типов данных. Для этого в языке определен набор фиксированных имен, каждое из которых является именем одной из констант, определяющих то или иное предельное значение. Например:
FLT__MAX — максимальное число с плавающей точкой типа float;
CHAR_BIT — количество битов в байте;
INT_MIN — минимальное значение для данных типа int.
Чтобы использовать в программе указанные именованные препроцессорные константы, недостаточно записать их имена в программе. Предварительно в текст программы необходимо включить препроцессорную директиву такого вида:
#include где в качестве имени_заголовочного_файла подставляются:
limits.h — для данных целых типов;
float.h — для вещественных данных.
В заголовочный файл limits.h помещаются, например, такие определения констант:
#define CHAR_BIT 8
#define SHRT_MAX Ox7FFF
#define LОNG MAX Ox7FFFFFFFL
В заголовочном файле float.h находятся директивы, определяющие константы, связанные с представлением данных вещественных типов. Например:
#define FLT_MIN 1.17549435E-38F
#define DBL_MIN 2.2250738585072014E-308
#define DBL_EPSILОN 2.2204460492503131E-16
Итак, записав в тексте своей программы директиву
можно использовать в программе стандартные именованные константы CHAR_BIT, SHRT_MIN и т.д.
Если включить в программу директиву
то станут доступными именованные константы предельных значений числовых данных вещественных типов.
Такой подход к определению предельных значений с помощью препроцессорных констант, сохраняемых в библиотечных файлах, позволяет писать программы, не зависящие от реализации, что обеспечивает их достаточную мобильность. Программист использует в программе стандартные имена (обозначения) констант, а их значения определяются версией реализации, т.е. конкретным компилятором и его библиотеками.
В этом параграфе определяются все операторы языка Си и приводится таблица их приоритетов.
1.6.1 Знаки операторов
Для формирования и последующего вычисления выражений используются операторы. Для изображения операторов в большинстве случаев используется несколько символов. В табл. 1.4 приведены все знаки операторов, определенные стандартом языка. Операторы в таблице разбиты на группы в соответствии с их рангами.
За исключением операторов «[]», «()» и «?:», все знаки операторов распознаются компилятором как отдельные лексемы. В зависимости от контекста одна и та же лексема может обозначать разные операторы, т.е. один и тот же знак операторы может употребляться в различных выражениях и по-разному интерпретироваться в зависимости от контекста. Например, бинарный оператор -это оператор получения адреса.
Операторы ранга 1 имеют наивысший приоритет. Операторы одного ранга имеют одинаковый приоритет. Если в выражении несколько операторов, то они выполняются в соответствии с правилом ассоциативности, либо слева направо (->), либо справа налево (<-). Если один и тот же знак оператор приведен в таблице дважды (например, знак *), то первое появление (с меньшим по номеру, т.е. старшим по приоритету, рангом) соответствует унарной операторы, а второе – бинарной.
Ранг | Операторы | Ассоциативность |
() [ ] ->. | -> | |
! ~ + — ++ — | ||
+ — (аддитивные бинарные) | -> | |
> (поразрядного сдвига) | — > | |
< = > (отношения) | -> | |
==!= (отношения) | -> | |
И») | -> | |
^ (поразрядное исключающее «ИЛИ») | -> | |
| (поразрядная дизъюнкция «ИЛИ») | -> | |
(конъюнкция «И») | -> | |
|| (дизъюнкция «ИЛИ») | -> | |
?: (условный оператор) | ||
= *= /= %= += -= >= | ||
, (оператор «запятая») | -> |
Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:
Источник: studopedia.ru
Решение модуля 13.3 из курса «Поколение Python: для начинающих»
Демонстрирую решения на курс «Поколение Python: курс для начинающих» и модуль (урок) 13.3.
Переменная, которая создается внутри функции называется
Часть программы, в которой можно получать доступ к переменной, называется
Что покажет приведенная ниже программа?
def print_paris(): print(s) s = ‘I love Paris’ print_paris()
UnboundLocalError: local variable ‘s’ referenced before assignment
Разрешается ли, чтобы локальная переменная в одной функции имела то же имя, что и локальная переменная в другой функции?
Что покажет приведенная ниже программа?
def print_paris():
s = ‘I love Paris’
print(s)def print_london():
s = ‘I love London’
print(s)s = ‘I love Moscow’
print_paris()
print_london()
print(s)
I love Paris I love London I love Moscow
Что покажет приведенная ниже программа?
def swap(a, b):
a, b = b, aa = 4
b = 3
swap(a, b)
print(a — b)
Какие из переменных в приведенном ниже коде являются локальными?
number = 101
def is_prime(num):
flag = True
for i in range(2, num):
if num % i == 0:
flag = False
break
if num != 1 and flag == True:
print(‘Число’, num, ‘простое.’)
else:
print(‘Число’, num, ‘составное.’)x = 17
y = int(input())
is_prime(x)
is_prime(y)
is_prime(number)
num, i, flag
Переменная, которая видима любой функции в программном файле, называется
По мере возможности вам следует избегать использования в программе
Что покажет приведенная ниже программа?
x = 5
def add():
x = 3
x = x + 5
print(x)add()
print(x)
Что покажет приведенная ниже программа?
x = 5
def add():
global x
x = 3
x = x + 5
print(x)add()
print(x)
Все утверждения верные — отметить все.
Источник: zazloo.ru