Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
OOP.doc
Скачиваний:
7
Добавлен:
25.04.2019
Размер:
1.34 Mб
Скачать

Вопросы для самопроверки

  1. Какие функции принято называть дружественными?

  2. Как описать и определить дружественную функцию?

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

  4. В каком случае при вызове дружественной функции можно использовать операции ‘.’, ‘–>’, ‘.*’, ‘–>*’ ? Поясните ответ.

  5. Каким образом можно определить дружественную функцию к вложенному классу? Приведите пример.

  6. Как дружественная функция получает доступ к компонентам объекта класса, предоставляющего «дружбу»?

  7. Класс C объявлен дружественным к классу B, а класс B является дружественным к классу A. Как сделать класс C дружественным к классу A? Приведите эскиз кода.

  8. Можно ли сделать некоторый класс дружественным к иерархии классов? Если можно, то как? Поясните ответ примером.

  9. Имеется класс class C { class A {}; class B {}; }; Как обеспечить неограниченный доступ классов C::A и C::B друг к другу?

  10. Как можно сделать функцию, дружественную по отношению к иерархии классов, виртуальной к этой иерархии? Приведите фрагмент кода.

  11. Каким образом можно имитировать «наследование» дружественности функций в классовых иерархиях? Приведите фрагмент кода.

Задачи

  1. Разработать класс CSegment, представляющий отрезки на плоскости, а также класс CSquare, описывающий квадраты. Квадрат реализовать на основе четырех отрезков. При этом для обеспечения эффективности использовать отношение дружественности между классами CSquare и CSegment.

  2. Определить класс CSheet, описывающий лист бумаги, на котором можно делать заметки. Также разработать класс CNotebook, отображающий свойства виртуальной записной книжки. Для реализации последнего использовать функциональность класса CSheet. Для обеспечения эффективности установить отношение дружественности между классами CSheet и CNotebook.

4. Механизм вложения

Любой класс в качестве компонента может содержать другой класс. Такое отношение, называемое отношением вложенности, обычно используется тогда, когда один класс (объемлющий) реализуется посредством другого (вложенного). Примером является класс, представляющий квадраты на плоскости (объемлющий), и класс, описывающий отрезки (вложенный), посредством которого можно реализовать класс квадратов (см. задачу 1 из главы 3). Еще один пример. Объемлющим классом является класс, описывающий матрицы. Вложенный – класс, описывающий одномерные массивы. Одномерный массив может представлять строку объекта-матрицы. Соответственно, компоненты такого массива могут использоваться матрицей для реализации ее функциональности (так, одномерный массив может включать функцию для суммирования всех элементов; в матрице эта функция будет суммировать элементы строки).

4.1. Вложенные классы

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

Представленный ниже пример иллюстрирует возможные способы определения вложенных классов и их компонент.

Пример

class CEnclosing { // определение объемлющего класса

public:

class CNested1; // объявление первого вложенного класса

class CNested2; // объявление второго вложенного класса

...

class CNested1 { // определение первого вложенного класса

public:

...

private:

static int __static_member;

};

};

// внешнее определение статического компонента

int CEnclosing::CNested1::__static_member = 1;

// внешнее определение второго вложенного класса

class CEnclosing::CNested2 {

public:

void SomeFunction1();

void SomeFunction2() { // внутреннее определение функции

...

}

...

};

// внешнее определение функции второго вложенного класса

void CEnclosing::CNested2::SomeFunction1() { /* ... */ }

Особый интерес при работе с вложенными классами представляет взаимная доступность компонент объемлющего и вложенного классов. Компоненты вложенного класса могут иметь доступ только к открытым компонентам объемлющего класса. Справедливо и обратное: компоненты объемлющего класса могут иметь доступ только к открытым компонентам вложенного класса. Из указанных открытых компонент (как объемлющего, так и вложенного классов) непосредственно доступны только статические компоненты, имена типов и константы перечислений. Доступ к другим открытым компонентам требует указания объекта объемлющего / вложенного класса. Доступ к закрытым и защищенным компонентам возможен только при условии дружественности объемлющего и вложенного классов (дружественность может быть как односторонней, так и взаимной).

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

Пример

int x, y;

class CEnclosing {

public:

int x;

static int s;

enum { const1 = 1, const2 = 2 };

class CInner {

public:

void f(int i) {

x = i; // ошибка, неясно к какому объекту относится x

s = i; // нормально, инициализация статического компонента

::x = i; // нормально, доступ к глобальным переменным

y = ::x;

// нормально, работаем с элементами перечисления

y = const1 + const2;

}

void g(CEnclosing * p, int i) {

p->x = i; // нормально, работаем с объектом *p

p->h(1); // ошибка, функция h недоступна

}

private:

static int q;

friend class CEnclosing;

};

protected:

void h(int i) {

CInner::q = i;

// нормально, компонент q доступен в силу дружественности

}

};

Вложенный класс, в принципе, является обычным классом; он просто локализован в пространстве имен объемлющего класса. Соответственно, он может быть базовым и/или производным классом. И еще одна интересная особенность. Интерфейс вложенного класса всегда включается в интерфейс объемлющего класса, т.е. все public-компоненты вложенного класса остаются открытыми независимо от того, в какой части объемлющего класса определен вложенный класс.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]