C++. Бархатный путь. Часть 2 - Синтаксис объявления членов класса

ОГЛАВЛЕНИЕ

 

Синтаксис объявления членов класса

Мы продолжаем формальное определение класса. Теперь рассмотрим синтаксис объявления членов класса.

СписокЧленов ::= ОбъявлениеЧленаКласса [СписокЧленов]
::= СпецификаторДоступа : [СписокЧленов]
ОбъявлениеЧленаКласса ::= [СписокСпецификаторовОбъявления]
[СписокОписателейЧленовКласса];
::= ОбъявлениеФункции
::= ОпределениеФункции [;]
::= КвалифицированноеИмя;
СписокОписателейЧленовКласса ::= ОписательЧленаКласса
::= СписокОписателейЧленовКласса,
ОписательЧленаКласса
ОписательЧленаКласса ::= Описатель [ЧистыйСпецификатор]
::= [Идентификатор] : КонстантноеВыражение
ЧистыйСпецификатор ::= = 0
КвалифицированноеИмяКласса ::= ИмяКласса
::= ИмяКласса :: КвалифицированноеИмяКласса
СпецификаторДоступа ::= private
::= protected
::= public

Список членов определяет полный набор членов данного класса. В этом списке объявляются все члены класса. Таковыми могут быть данные, функции-члены, ранее объявленные классы, перечисления, битовые поля, дружественные функции и даже имена типов. Некоторые из перечисленных понятий нам уже знакомы, о других речь ещё впереди. Этот список не подлежит модификации. Он формируется за один раз.

В соответствии с синтаксическими правилами, членами класса могут быть как определения функций, так и их прототипы. Действительно:

ОбъявлениеЧленаКласса ::= 
[СписокСпецификаторовОбъявления] [СписокОписателейЧленовКласса]; ::=
СпецификаторОбъявления ОписательЧленаКласса; ::=
СпецификаторТипа Описатель; ::=
void Описатель (СписокОбъявленийПараметров); ::=
void ff (void);

С другой стороны,

ОбъявлениеЧленаКласса ::= 
ОпределениеФункции [;] ::=
Описатель (СписокОбъявленийПараметров) ТелоФункции ::=
ff (void) {int iVal = 100;}

В соответствии с синтаксическими правилами, членами класса могут быть как определения функций, так и их прототипы. Действительно:

ОбъявлениеЧленаКласса ::= 
[СписокСпецификаторовОбъявления] [СписокОписателейЧленовКласса]; ::=
СпецификаторОбъявления ОписательЧленаКласса; ::=
СпецификаторТипа Описатель; ::=
void Описатель (СписокОбъявленийПараметров); ::=
void ff (void);

С другой стороны,

ОбъявлениеЧленаКласса ::= 
ОпределениеФункции [;] ::=
Описатель (СписокОбъявленийПараметров) ТелоФункции ::=
ff (void) {int iVal = 100;}

Точка с запятой после определения функции является декоративным элементом. Ни один член класса не может входить в список членов класса дважды. Поэтому определяемая в теле класса функция оказывается без прототипа. Если класс содержит прототип функции в качестве члена класса, функция располагается за пределами класса. Как мы скоро увидим, всё разнообразие объявлений и определений функций-членов транслятор приводит к единому стандартному виду.

Функции-члены могут определяться вне списка членов класса. При определении функции-члена класса за пределами данного класса, в списке членов класса размещается прототип функции-члена. А при определении функции-члена используется квалифицированное имя. Квалифицированное имя состоит из последовательности имён классов, разделённых операциями разрешения области видимости. Эта последовательность имён завершается именем определяемой функции. Последовательность имён классов в квалифицированных именах определяется степенью вложенности объявлений классов.

Наличие функций-членов делает объявление класса подобным определению (как и любые функции, функции-члены определяются). Как сказано в Справочном руководстве по C++, "Если бы не исторические причины, объявление класса следовало называть определением класса".

Данные-члены класса не могут объявляться со спецификаторами auto, extern, register.

Ни при каких обстоятельствах не допускается объявление одноименных членов. Имена данных-членов должны также отличаться от имён функций-членов. Использование одноимённых функций, констант и переменных в выражениях в пределах одной области действия имён приводит к неоднозначности. Как известно, имя функции, как и имя константы и переменной, является выражениями. Если допустить объявление одноимённых переменных, констант и функций, то в ряде случаев просто невозмо будет определить, о чём в программе идёт речь.

Объявляемые в классе данные-члены, которые являются представителями классов, должны представлять ранее объявленные классы. Транслятор должен знать заранее о структуре подобных данных-членов. 

Описатель члена класса в объявлении класса не может содержать инициализаторов (это всего лишь объявление).

Структура является классом, объявленным с ключевым словом класса struct. Члены такого класса и базовые классы по умолчанию обладают спецификацией доступа public.

Назначение спецификаторов доступа будет обсуждаться в разделах, посвящённых управлению доступом. Пока будет достаточно в объявлении класса указать спецификатор public. В этом случае члены класса оказываются доступны (к ним можно будет свободно обращаться) из любого оператора программы.

Объединение является классом, объявленным с ключевым словом класса union. Его члены также по умолчанию обладают спецификацией доступа public. В каждый момент исполнения программы объединение включает единственный член класса. В этом его специфика. Именно поэтому не может быть пустого объединения. Позже мы вернёмся к объединениям.

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

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