Классы и структуры – родственные типы



 

Как упоминалось в предыдущей главе, в C++ структура также обладает объектно‑ориентированными возможностями. В сущности, классы и структуры можно назвать близкими родственниками. За одним исключением, они взаимозаменяемы, поскольку структура также может включать данные и код, который манипулирует этими данными точно так же, как это может делать класс. Единственное различие между С++‑структурой и С++‑классом состоит в том, что по умолчанию члены класса являются закрытыми, а члены структуры – открытыми. В остальном же структуры и классы имеют одинаковое назначение. На самом деле в соответствии с формальным синтаксисом C++ объявление структуры создает тип класса.

Рассмотрим пример структуры со свойствами, подобными свойствам класса.

 

 

В этой программе определяется тип структуры с именем cl , в которой функции‑члены get_i() и put_i() являются открытыми (public), а член данных i – закрытым (private). Обратите внимание на то, что в структурах для объявления закрытых членов используется ключевое слово private .

Ключевое слово private используется для объявления закрытых членов класса.

В следующем примере показана эквивалентная программа, которая использует вместо типа struct тип class .

 

 

Иногда С++‑программисты к структурам, которые не содержат функции‑члены, применяют термин POD‑struct.

С++‑программисты тип class используют главным образом для определения формы объекта, который содержит функции‑члены, а тип struct – для создания объектов, которые содержат только члены данных. Иногда для описания структуры, которая не содержит функции‑члены, используется аббревиатура POD (Plain Old Data).

 

Сравнение структур с классами

 

Тот факт, что и структуры, и классы обладают практически идентичными возможностями, создает впечатление избыточности. Многие новички в программировании на C++ недоумевают, почему в нем существует такое очевидное дублирование. Нередко приходится слышать предложения отказаться от ненужного ключевого слова (class или struct ) и оставить только одно из них.

Ответ на эту цепь рассуждений лежит в происхождении языка C++ от С и намерении сохранить C++ совместимым снизу вверх с С. В соответствии с современным определением C++ стандартная С‑структура одновременно является совершенно законной С++‑структурой. В языке С, который не содержит ключевых слов public или private , все члены структуры являются открытыми. Вот почему и члены С++‑структур по умолчанию являются открытыми (а не закрытыми). Поскольку конструкция типа class специально разработана для поддержки инкапсуляции, есть определенный смысл в том, чтобы по умолчанию ее члены были закрытыми. Следовательно, чтобы избежать несовместимости с языком С в этом вопросе, аспекты доступа, действующие по умолчанию, менять было нельзя, поэтому и решено было добавить новое ключевое слово. Но в перспективе можно говорить о более веской причине для отделения структур от классов. Поскольку тип class синтаксически отделен от типа struct , определение класса вполне открыто для эволюционных изменений, которые синтаксически могут оказаться несовместимыми с С‑подобными структурами. Поскольку мы имеем дело с двумя отдельными типами, будущее направление развития языка C++ не обременяется "моральными обязательствами" , связанными с совместимостью с С‑структурами.

Под "занавес" этой темы отметим следующее. Структура определяет тип класса. Следовательно, структура является классом. На этом настаивал создатель языка C++, Бьерн Страуструп. Он полагал, что если структура и классы будут более или менее эквивалентны, то переход от С к C++ станет проще. И история доказала его правоту!

 

Объединения и классы – родственные типы

 

Тот факт, что структуры и классы – родственны, обычно никого не удивляет; однако вы можете удивиться, узнав, что объединения также связаны с классами "близкими отношениями". Согласно определению C++ объединение – это, по сути, тот же класс, в котором все члены данных хранятся в одной и той же области. (Таким образом, объединение также определяет тип класса.) Объединение может содержать конструктор и деструктор, а также функции‑члены. Конечно же, члены объединения по умолчанию открыты (public), а не закрыты (private).

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

 

 

Подобно структуре, С++‑объединение также произошло от своего С‑предшественника. Но в C++ оно имеет более широкие "классовые" возможности. Однако лишь то, что C++ наделяет "свои" объединения более могучими средствами и большей степенью гибкости, не означает, что вы непременно должны их использовать. Если вас вполне устраивает объединение с традиционным стилем поведения, вы вольны именно таким его и использовать. Но в случаях, когда можно инкапсулировать данные объединения вместе с функциями, которые их обрабатывают, все же стоит воспользоваться С++‑возможностями, что придаст вашей программе дополнительные преимущества.

 

Встраиваемые функции

 

Прежде чем мы продолжим освоение класса, сделаем небольшое, но важное отступление. Оно не относится конкретно к объектно‑ориентированному программированию, но является очень полезным средством C++, которое довольно часто используется в определениях классов. Речь идет о встраиваемой , или подставляемой , функции (inline function ). Встраиваемой называется функция, код которой подставляется в то место строки программы, из которого она вызывается, т.е. вызов такой функции заменяется ее кодом. Существует два способа создания встраиваемой функции. Первый состоит в использовании модификатора inline . Например, чтобы создать встраиваемую функцию f() , которая возвращает int ‑значение и не принимает ни одного параметра, достаточно объявить ее таким образом.

 

 

Модификатор inline должен предварять все остальные аспекты объявления функции.

Встраиваемая функцияэто небольшая (по объему кода) функция, код которой подставляется вместо ее вызова.

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

Продемонстрируем использование встраиваемой функции на примере следующей программы.

 

 

Здесь вместо вызова функций get_i() и put_i() подставляется их код. Так, в функции main() строка

 

 

функционально эквивалентна следующей инструкции присваивания:

 

 

Поскольку переменная i по умолчанию закрыта в рамках класса cl , эта строка не может реально существовать в коде функции main() , но за счет встраивания функции put_i() мы достигли того же результата, одновременно избавившись от затрат системных ресурсов, связанных с вызовом функции.

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

■ Некоторые компиляторы не генерируют встраиваемый код, если соответствующая функция содержит цикл, конструкцию switch или инструкцию goto .

■ Чаще всего встраиваемыми не могут быть рекурсивные функции.

■ Как правило, встраивание "не проходит" для функций, которые содержат статические (static) переменные.

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

 


Дата добавления: 2018-09-22; просмотров: 331; Мы поможем в написании вашей работы!

Поделиться с друзьями:






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