C++. Бархатный путь. Часть 2 - Класс. Объявление класса
ОГЛАВЛЕНИЕ
Класс. Объявление класса
Класс - это тип. Этот производный тип вводится в программу с помощью специального оператора объявления класса. В объявлении класса используется ранее описанный инструментальный набор средств для построения и преобразования производных типов.
Очередное множество форм Бэкуса-Наура определяет синтаксис объявления класса.
Объявление ::= [СписокСпецификаторовОбъявления] [СписокОписателей];
СписокСпецификаторовОбъявления
::= [СписокСпецификаторовОбъявления] СпецификаторОбъявления
СпецификаторОбъявления ::= СпецификаторТипа
::= *****
СпецификаторТипа ::= СпецификаторКласса
::= УточнённыйСпецификаторТипа
::= *****
УточнённыйСпецификаторТипа ::= КлючевоеСловоКласса ИмяКласса
::= КлючевоеСловоКласса Идентификатор
::= enum ИмяПеречисления
КлючевоеСловоКласса ::= union
::= struct
::= class
ИмяКласса ::= Идентификатор
СпецификаторКласса ::= ЗаголовокКласса {[СписокЧленов]}
ЗаголовокКласса
::= КлючевоеСловоКласса [Идентификатор] [СпецификацияБазы]
::= КлючевоеСловоКласса ИмяКласса [СпецификацияБазы]
КлючевоеСловоКласса ::= union
::= struct
::= class
ИмяКласса ::= Идентификатор
Спецификатор класса представляет то, что называется объявлением класса. Уточнённый спецификатор типа объявляет расположенный за ним идентификатор именем класса. Уточнённый спецификатор обеспечивает неполное предварительное объявление класса и перечисления.
Назначение и смысл необязательного нетерминального символа СпецификацияБазы будут обсуждаться позже, в разделах, посвящённых наследованию.
Предварительное объявление обеспечивается уточнённым спецификатором типа и является своеобразным прототипом класса или перечисления. Его назначение - сообщение транслятору предварительной информации о том, что существует (должно существовать) объявление класса (или перечисления) с таким именем. Идентификатор, используемый в контексте уточнённого спецификатора имени становится именем класса (или именем перечисления).
Класс считается объявленным даже тогда, когда в нём полностью отсутствует информация о членах класса (пустой список членов класса). Неименованный класс с пустым множеством членов - уже класс!
Имя класса можно употреблять как имя (имя типа) уже в списке членов этого самого класса.
Класс может быть безымянным.
Следующая последовательность операторов объявления
class {}; /* Объявлен пустой неименованный класс.*/
class {};
class {};
class {};
/* Это всё объявления. Их количество ничем не ограничивается. */
struct {};
/* Структура - это класс, объявленный с ключевым словом struct.
Опять же пустой и неименованный.*/
не вызывает у транслятора никаких возражений.
На основе класса, пусть даже неименованного, может быть объявлен (вернее, определён) объект-представитель этого класса. В таком контексте объявление неименованного (пусть даже и пустого!) класса является спецификатором объявления. Имена определяемых объектов (возможно с инициализаторами) составляют список описателей.
class {} Obj1, Obj2, Obj3;/* Здесь объявление пустого класса.*/
class {} Obj4, Obj5, Obj6;/* Просто нечего инициализировать.*/
class {} Obj1;
/* ^ Ошибка. Одноименные объекты в области действия имени.*/
Неименованные классы также можно применять в сочетании со спецификатором typedef (здесь может быть объявление класса любой сложности - не обязательно только пустой). Спецификатор typedef вводит новое имя для обозначения безымянного класса. Описанное имя типа становится его единственным именем.
Сочетание спецификатора typedef с объявлением безымянного класса подобно объявлению класса с именем:
class MyClass {/*…*/};
typedef class {/*…*/} MyClass;
Правда в первом случае класс имеет собственное имя класса, а во втором - описанное имя типа. Использование описанного имени типа в пределах области действия имени делает эквивалентными следующие определения (и им подобные):
class {} Obj1;
MyClass Obj1;
Класс считается объявленным лишь после того, как в его объявлении будет закрыта последняя фигурная скобка. До этого торжественного момента информация о структуре класса остаётся неполной.
Если можно ОБЪЯВИТЬ пустой класс, то можно ОПРЕДЕЛИТЬ и объект-представитель пустого класса. Эти объекты размещаются в памяти. Их размещение предполагает выделение объекту участка памяти с уникальным адресом, а это означает, что объекты пустого класса имеют ненулевой размер.
Действительно, значения выражений sizeof(MyClass) и sizeof(MyObj1) (это можно очень просто проверить) отличны от нуля.
А вот пустое объединение (ещё одна разновидность класса - класс, объявленный с ключевым словом union) не объявляется:
union {}; /* Некорректное объявление объединения. */
При объявлении объединения требуется детальная информация о внутреннем устройстве этого объединения.