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

Классы (и структуры) могут быть объявлены внутри другого класса или даже внутри какого-либо метода. Такие классы называются вложенными.

Обычные вложенные классы

Если объявление класса расположено внутри другого класса, то такой класс можно скрыть от внешнего кода, добавив его в раздел private. Начиная со стандарта C++11, вложенный класс является другом внешнего класса, поэтому внутри вложенного класса мы имеем доступ:

  • к статическим членам внешнего класса, включая закрытые. Перед именем статического члена указывается название внешнего класса и оператор ::. Пример:
std::cout << A::z << ' ';
  • к обычным членам класса, включая закрытые, через экземпляр внешнего класса:
void A::B::print(A &o) {
   std::cout << o.y_ << std::endl;
}

По умолчанию внешний класс не является другом вложенного класса и не имеет доступа к закрытым членам вложенного класса. Чтобы получить доступ к закрытым членам вложенного класса нужно внутри объявления вложенного класса добавить инструкцию:

friend class Название_внешнего_класса;

При определении методов вложенного класса отдельно от объявления класса, перед названием метода через оператор :: указываются названия внешнего и вложенного классов:

void A::B::func() { std::cout << "A::B::func() " << std::endl; }

Пример использования вложенного класса приведен в листинге 13.34.

Листинг 13.34. Вложенные классы

#include <iostream>

class A {                                // Внешний класс
private:
   class B {                             // Вложенный класс
      friend class A;
      int x_;
   public:
      B(int x) : x_(x) { }
      void func();
      void print(A &o);
   };

   B objB;
   int y_;
   static int k_;
public:
   A(int x, int y) : objB(x), y_(y) { }
   int getY() { return y_; }
   int getX() { return objB.x_; }        // friend class A;
   void test();

   static int z;
};

int A::z = 12;
int A::k_ = 14;
void A::B::func() { std::cout << "A::B::func() " << x_ << std::endl; }
void A::B::print(A &o) {
   // std::cout << y_ << std::endl;      // Нет доступа
   // error: invalid use of non-static data member 'A::y_'
   std::cout << A::z << ' ';             // OK (public static)
   std::cout << A::k_ << ' ';            // OK (private static)
   std::cout << o.y_ << std::endl;       // OK (private y_)
}
void A::test() {
   objB.func();
   objB.print(*this);
}

int main() {
   A obj(10, 20);
   obj.test();                           // A::B::func() 10
                                         // 12 14 20
   std::cout << obj.getY() << std::endl; // 20
   std::cout << obj.getX() << std::endl; // 10
   return 0;
}

Если вложенный класс объявлен общедоступным (public), то мы можем создать экземпляр вложенного класса, указав в качестве типа переменной название внешнего класса, после которого идет оператор :: и название вложенного класса. Например, изменим строку 4 из листинга 13.34:

private:

следующим образом:

public:

Теперь внутри функции main() мы можем создать экземпляр класса B:

A::B obj2(30);
obj2.func();       // A::B::func() 30

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

public:
   typedef B AB;

Доступ к вложенному классу через псевдоним внутри функции main() осуществляется так:

A::AB obj3(40);    // Внешний_класс::Псевдоним Объект(40);
obj3.func();       // A::B::func() 40

Локальные вложенные классы

Класс может быть вложен в блок функции (или метода какого-либо класса). Такие классы называются локальными вложенными классами. Перечислим особенности использования локальных вложенных классов:

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

Пример использования локального вложенного класса приведен в листинге 13.35.

Листинг 13.35. Локальные вложенные классы

#include <iostream>

int a = 30;
void print(int n) {
   std::cout << n << std::endl;
}
void func() {
   int z = 40;
   const int M = 50;
   class Point {          // Локальный вложенный класс
      int x_, y_;
   public:
      Point(int x, int y): x_(x), y_(y) { }
      int getX() { return x_; }
      int getY() { return y_; }
      void test() {
         print(a);    // Доступ к глобальной переменной и функции
         // print(z); // Доступа к локальной переменной нет
         print(M);    // Доступ к локальной константе
      }
      static int sum(int x, int y) { // Статический метод
         return x + y;
      }
   };

   Point obj(10, 20);
   std::cout << obj.getX() << std::endl; // 10
   std::cout << obj.getY() << std::endl; // 20
   obj.test();                           // 30
                                         // 50
   std::cout << z << std::endl;          // 40
   std::cout << Point::sum(10, 20);      // 30
}

int main() {
   func();
   return 0;
}

Учебник C++ (Qt Creator и MinGW)
Учебник C++ (Qt Creator и MinGW) в формате PDF

Помощь сайту

ЮMoney (Yandex-деньги): 410011140483022

ПАО Сбербанк:
Счет: 40817810855006152256
Реквизиты банка:
Наименование: СЕВЕРО-ЗАПАДНЫЙ БАНК ПАО СБЕРБАНК
Корреспондентский счет: 30101810500000000653
БИК: 044030653
КПП: 784243001
ОКПО: 09171401
ОКОНХ: 96130
Скриншот реквизитов