Розглянемо наступний код:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
#include <iostream> enum FruitList { AVOCADO, BLACKBERRY, LEMON }; class Fruit { private: FruitList m_type; public: Fruit(FruitList type) : m_type(type) { } FruitList getType() { return m_type; } }; int main() { Fruit avocado(AVOCADO); if (avocado.getType() == AVOCADO) std::cout << "I am an avocado!"; else std::cout << "I am not an avocado!"; return 0; } |
У цій програмі все працює. Але оскільки перерахування FruitList використовується в зв’язці з класом Fruit, то трохи дивно, що воно існує окремо від самого класу.
Вкладені користувацькі типи даних в класах
На відміну від функцій, які не можуть бути вкладені (знаходяться всередині одна одної), в мові C++ користувацькі типи даних можуть бути визначені (вкладені) всередині класу. Для цього потрібно просто визначити користувацький тип всередині класу під відповідним специфікатором доступу.
Ось вищенаведена програма, але вже з FruitList, визначеним всередині класу:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
#include <iostream> class Fruit { public: // Ми перемістили FruitList всередину класу під специфікатор доступу public enum FruitList { AVOCADO, BLACKBERRY, LEMON }; private: FruitList m_type; public: Fruit(FruitList type) : m_type(type) { } FruitList getType() { return m_type; } }; int main() { // Доступ до FruitList здійснюється через Fruit Fruit avocado(Fruit::AVOCADO); if (avocado.getType() == Fruit::AVOCADO) std::cout << "I am an avocado!"; else std::cout << "I am not an avocado!"; return 0; } |
Зверніть увагу:
По-перше, FruitList тепер визначений всередині тіла класу.
По-друге, ми визначили його під специфікатором доступу public, тобто зробили доступ до FruitList відкритим.
По суті, класи працюють як простори імен для будь-яких вкладених типів даних. У першому прикладі ми маємо доступ до енумератора AVOCADO
напряму, так як AVOCADO
визначений в глобальній області видимості (ми могли б запобігти цьому, використовуючи клас enum замість звичайного enum, і тоді доступ до AVOCADO
здійснювався б через FruitList::AVOCADO
). Тепер, оскільки FruitList рахується частиною класу, доступ до енумератора AVOCADO
здійснюється через ім’я класу, наприклад: Fruit::AVOCADO
.
Зверніть увагу, оскільки класи enum також працюють як простори імен, і якщо б ми помістили клас enum (замість звичайного enum) з ім’ям FruitList всередину класу Fruit, то доступ до енумератора AVOCADO
здійснювався б через Fruit::FruitList::AVOCADO
.
Інші вкладені користувацькі типи даних в класах
Хоча перерахування є найбільш поширеним вкладеним користувацьким типом даних всередині класів, мова C++ також дозволяє визначати і інші користувацькі типи всередині класів, такі як псевдоніми типів (typedef і type alias) і навіть інші класи!
Як і будь-який звичайний член класу, вкладений клас матиме доступ до всіх членів класу-оболонки (в якому він розміщений). Однак вкладені класи не мають доступу до вказівника *this класу-оболонки.
Визначення вкладених типів не дуже поширено, але Стандартна бібліотека C++ все ж використовує це в деяких випадках. Про це детально ми поговоримо на відповідному уроці.