Выбрать главу

В содержащем классе вложенный класс представляет собой член, типом которого является класс. Подобно любому другому члену, содержащий класс задает уровень доступа к этому типу. Вложенный класс, определенный в разделе public содержащего класса, может быть использован везде. Вложенный класс, определенный в разделе protected, доступен только содержащему классу, его производным и дружественным классам. Вложенный класс, определенный в разделе private, доступен лишь для членов содержащего класса и классов, дружественных для него.

Объявление вложенного класса

Класс TextQuery из раздела 12.3.2 определял сопутствующий класс QueryResult. Класс QueryResult жестко связан с классом TextQuery. Класс QueryResult имело бы смысл использовать и для других целей, а не только для результатов операции запроса к объекту класса TextQuery. Для отражения этой жесткой связи сделаем класс QueryResult членом класса TextQuery.

class TextQuery {

public:

 class QueryResult; // вложенный класс будет определен позже

 // другие члены, как в разделе 12.3.2

};

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

Определение вложенного класса вне содержащего класса

В классе TextQuery класс QueryResult объявлен, но не определен. Подобно функциям-членам, вложенные классы следует объявить в классе, но определен он может быть в или вне класса.

При определении вложенного класса вне его содержащего класса следует квалифицировать имя вложенного класса именем его содержащего класса:

// определение класса QueryResult как члена класса TextQuery

class TextQuery::QueryResult {

 // в области видимости класса не нужно квалифицировать имя

 // параметров QueryResult

 friend std::ostream&

  print(std::ostream&, const QueryResult&);

public:

 // не нужно определять QueryResult::line_no; вложенный класс способен

 // использовать член своего содержащего класса без необходимости

 // квалифицировать его имя

 QueryResult(std::string,

  std::shared_ptr<std::set<line_no>>,

  std::shared_ptr<std::vector<std::string>>);

 // другие члены, как в разделе 12.3.2

};

Единственное изменение, внесенное в первоначальный класс, заключается в том, что в классе QueryResult больше не определяется переменная-член line_no. Члены класса QueryResult могут обращаться к этому имени непосредственно в классе TextQuery, таким образом, нет никакой необходимости определять его снова.

Пока не встретится фактическое определение вложенного класса, расположенное вне тела класса, этот класс является незавершенным типом (см. раздел 7.3.3).

Определение членов вложенного класса

В этой версии конструктор QueryResult() не определяется в теле класса. Чтобы определить конструктор, следует указать, что класс QueryResult вложен в пределы класса TextQuery. Для этого имя вложенного класса квалифицируют именем содержащего его класса:

// определение члена класса по имени QueryResult для класса по

// имени QueryResult, вложенного в класс TextQuery

TextQuery::QueryResult::QueryResult(string s,

                                    shared_ptr<set<line_no>> p,

                                    shared_ptr<vector<string>> f):

 sought(s), lines (p), file(f) { }

Читая имя функции справа налево, можно заметить, что это определение конструктора для класса QueryResult, который вложен в пределы класса TextQuery. Сам код только сохраняет данные аргументов в переменных-членах и не делает больше ничего.