Внутреннее объявление класса

Возможный дубликат:
Плюсы и минусы использования вложенных классов C ++ и перечислений?

Рассмотрим следующую декларацию.

class A {
public:
class B{
};
};

Ничего особенного.

  • Но каковы преимущества этого?
  • Какие могут быть причины для помещения одного класса в другой?
  • Между обоими классами нет преимущества наследования.
  • Если B помещается внутри A для совместного использования его частных имен, то A для B является просто пространством имен, и есть причина также сделать B частным.

Что Вы думаете об этом?

2

Решение

Концептуально, это позволяет программисту (ам) знать, что класс B относится конкретно к классу A. Когда вы используете класс B вне класса A, вы должны использовать тип как A :: B, который каждый раз напоминает вам, что B является относится к А. Это не добавляет никакой функциональности, но показывает отношения.

Точно так же вам совсем не нужно использовать наследование / композицию или классы. Вы можете более или менее моделировать классы в C, просто используя структуры и функции. Это просто способ сделать код чище и понятнее, а программисту проще связать код с дизайном. Классы достигают этого гораздо больше, чем публичные подклассы, но это только пример.

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

4

Другие решения

Преимущество 1: аспект пространства имен

В самом деле, A обеспечивает пространство имен для Bи это может помочь нам структурировать наш код намного лучше. Рассмотрим конкретный пример с vector за A, а также iterator за B, Можно утверждать, что

class vector {
public:
class iterator { /*...*/ };

iterator begin() { /*...*/ }
};

легче набирать, читать и понимать, чем

class vector_iterator {
/*...*/
};

class vector {
public:
vector_iterator begin() { /*...*/ }
};

Соблюдайте, в частности:

  1. Когда два класса (vector а также iterator) зависят друг от друга, т. е. используют члены друг друга, вторая версия выше потребует, чтобы одно из двух было объявлено заранее, а в некоторых случаях взаимные зависимости типов могут привести к неразрешимым ситуациям. (Используя вложенные классы, намного легче избежать таких проблем, потому что в большинстве частей определения вложенного класса рассматривается внешний класс полностью определены. Это связано с §9.2 / 2.)

  2. У вас вполне может быть много других типов данных, которые поддерживают свои собственные iteratorнапример, linked_list, Используя вторую версию выше, вам нужно определить linked_list_iterator как отдельный класс. Имена классов будут становиться все длиннее и сложнее, чем больше добавленных вами «зависимых» типов и альтернативных типов.

Преимущество 2: шаблоны

Продолжая приведенный выше пример, рассмотрим теперь шаблон функции, который принимает контейнер (например, vector а также linked_list определено выше) в качестве аргументов и перебирает их:

template <typename Container>
void iterate(const Container &container) {
/*...*/
}

Внутри этой функции вы, очевидно, очень хотели бы использовать тип итератора Container, Если это вложенный тип, это легко:

typename Container::iterator

Но если это не так, вы должны принять тип итератора в качестве отдельного параметра шаблона:

template <typename Container, typename Iterator>
void iterate(const Container &container) {
/*...*/
Iterator it = container.begin();
/*...*/
}

И если этот тип итератора не появляется среди аргументов функции, компилятор не может даже угадать тип. Вы должны были бы явно добавить его в угловые скобки каждый раз, когда вы вызываете iterate функция.

Финальные заметки: Ничто из этого не имеет отношения к тому, объявлен ли вложенный класс как открытый или закрытый. Мои примеры выше предлагают ситуацию, в которой публичный вложенный тип явно предпочтительнее, потому что я полагаю, iterator Тип должен быть в состоянии использоваться вне класса контейнера.

1

Какие причины могут быть для помещения одного класса в другой?

  • Если вам нужно ограничить область действия B доступными только для A, то поможет определение внутреннего класса. Потому что он ограничивает область видимости класса локальной. Это локализация области вызова. Они называются более общим термином inner class declaration, Проверь это ссылка на сайт.
  • Этот стекопоток вопрос поможет вам понять больше.
0