Программирование >>  Инициализация объектов класса, структура 

1 ... 212 213 214 [ 215 ] 216 217 218 ... 395


class List {

public:

...

private:

объявление необходимо

class ListItem;

ListItem *list;

ListItem *at end;

/ / имя вложенного класса квафицировано именем объемщего класса

class List::ListItem {

public:

ListItem( int val=0 );

ListItem *next; int value;

В глобальном определении имя вложенного ListItem должно быть квалифицировано именем объемлющего класса List. Заметьте, что объявление ListItem в теле List опустить нельзя. Определение вложенного класса не может быть задано в глобальной области видимости, если предварительно оно не было объявлено членом объемлющего класса. Но при этом вложенный класс не обязательно должен быть открытым членом объемлющего.

Пока компилятор не увидел определения вложенного класса, разрешается объявлять лишь указатели и ссылки на него. Объявления членов list и at end класса List правильны несмотря на то, что ListItem определен в глобальной области видимости, поскольку оба члена - указатели. Если бы один из них был объектом, то его объявление в классе List

class List {

public:

...

private:

объявление необходимо class ListItem; ListItem *list;

ListItem at end; ошибка: неопределенна вложенн класс ListItem привело бы к ошибке компиляции:

Зачем определять вложенный класс вне тела объемлющего? Возможно, он поддерживает некоторые детали реализации ListItem, а нам нужно скрыть их от пользователей класса List. Поэтому мы помещаем определение вложенного класса в заголовочный файл, содержащий интерфейс List. Таким образом, определение ListItem может находиться лишь внутри исходного файла, включающего реализацию класса List и его членов.

Вложенный класс можно сначала объявить, а затем определить в теле объемлющего. Это позволяет иметь во вложенных классах члены, ссылающиеся друг на друга:



class List {

public:

public:

...

private:

объявление List::ListItem

class ListItem; class Ref {

pli имеет тип List::ListItem* ListItem *pli;

определение List::ListItem class ListItem {

pref имеет тип List::Ref*

Ref *pref;

Если бы ListItem не был объявлен перед определением класса Ref, то объявление члена pli было бы ошибкой.

Вложенный класс не может напрямую обращаться к нестатическим членам объемлющего, даже если они открыты. Любое такое обращение должно производиться через указатель,

class List { public:

int init( int ); private:

class List::ListItem { public:

ListItem( int val=0 );

void mf( const List S );

int value;

List::ListItem::ListItem { int val )

List::init() - нестатический член класса List

должен использоваться через объект или указатель на тип Li

value = init( val ); ошибка: неверное использование init

ссылку или объект объемлющего класса. Например:

При использовании нестатических членов класса компилятор должен иметь возможность идентифицировать объект, которому принадлежит такой член. Внутри функции-члена класса ListItem указатель this неявно применяется лишь к его членам. Благодаря неявному this мы знаем, что член value относится к объекту, для которого вызван конструктор. Внутри конструктора ListItem указатель this имеет тин ListItem*. Для доступа же к функции-члену init() нужен объект типа List или указатель типа List*.

Следующая функция-член mf() обращается к init() с помощью параметра-ссылки. Таким образом, init() вызывается для объекта, переданного в аргументе функции:



void List::ListItem::mf( List &i1 ) { memb = i1.init(); правильно:

memb = i1.init(); правильно: обращается к init() по сс1лке

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

class List {

public:

typedef int (*pFunc)();

enum ListStatus { Good, Empty, Corrupted };

...

private:

class ListItem { public:

void check status(); ListStatus status; правильно

pFunc action; правильно

... ...

типа - это либо имя typedef, либо имя перечисления, либо имя класса. Например:

pFunc, ListStatus и ListItem - все это вложенные имена типов в области видимости объемлющего класса List. К ним, а также к элементам перечисления ListStatus можно

void List::ListItem::check status()

ListStatus s = status; switch ( s ) {

case Empty: ... case Corrupted: ...

case Good: ...

обращаться в области видимости класса ListItem даже без квалификации:

Вне области видимости ListItem и List при обращении к статическим членам, именам типов и элементам перечисления объемлющего класса требуется оператор разрешения

List::pFunc myAction; правильно

области видимости:

List::ListStatus stat = List::Empty; правильно

При обращении к элементам перечисления мы не пишем:

List::ListStatus::Empty



1 ... 212 213 214 [ 215 ] 216 217 218 ... 395

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика