В содержащем классе вложенный класс представляет собой член, типом которого является класс. Подобно любому другому члену, содержащий класс задает уровень доступа к этому типу. Вложенный класс, определенный в разделе 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. Сам код только сохраняет данные аргументов в переменных-членах и не делает больше ничего.