typedef std::string::size_type pos;

private:

 pos cursor = 0;

 pos height = 0, width = 0;

 std::string contents;

};

Тип pos определен в части public класса Screen, поскольку пользователи должны использовать это имя. Пользователи класса Screen не обязаны знать, что он использует класс string для хранения своих данных. Определив тип pos как открытый член, эту подробность реализации класса Screen можно скрыть.

В объявлении типа pos есть два интересных момента. Во-первых, хоть здесь и был использован оператор typedef (см. раздел 2.5.1), с таким же успехом можно использовать псевдоним типа (см. раздел 2.5.1):

class Screen {

public:

 // альтернативный способ объявления типа-члена с использованием

 // псевдонима типа

 using pos = std::string::size_type;

 // другие члены как прежде

};

Во-вторых, по причинам, которые будут описаны в разделе 7.3.4, в отличие от обычных членов, типы-члены определяются прежде, чем используются. В результате типы-члены обычно располагают в начале класса.

Функции-члены класса Screen

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

class Screen {

public:

 typedef std::string::size_type pos;

 Screen() = default; // необходим, поскольку у класса Screen есть

                     // другой конструктор

 // внутриклассовый инициализатор инициализирует курсор значением 0

 Screen(pos ht, pos wd, char c) : height(ht), width(wd),

                                  contents(ht * wd, c) { }

 char get() const // получить символ в курсоре

 { return contents [cursor]; }          // неявно встраиваемая

 inline char get(pos ht, pos wd) const; // явно встраиваемая

 Screen &move(pos r, pos с); // может быть сделана встраиваемой позже

private:

 pos cursor = 0;

 pos height = 0, width = 0;

 std::string contents;

};

Поскольку мы предоставляем конструктор, компилятор не будет автоматически создавать стандартный конструктор сам. Если у нашего класса должен быть стандартный конструктор, то придется создать его явно. В данном случае используется синтаксис = default, чтобы попросить компилятор самому создать определение стандартного конструктора (см. раздел 7.1.4).

Стоит также обратить внимание на то, что второй конструктор (получающий три аргумента) неявно использует внутриклассовый инициализатор для переменной-члена cursor (см. раздел 7.1.4). Если бы у класса не было внутриклассового инициализатора для переменной-члена cursor, то мы явно инициализировали бы ее наряду с другими переменными-членами.

Встраиваемые члены класса

У классов зачастую бывают небольшие функции, которые выгодно сделать встраиваемыми. Как уже упоминалось, определенные в классе функции-члены автоматически являются встраиваемыми (inline) (см. раздел 6.5.2). Таким образом, конструкторы класса Screen и версия функции get(), возвращающей обозначенный курсором символ, являются встраиваемыми по умолчанию.

Функцию-член можно объявить встраиваемой явно в ее объявлении в теле класса. В качестве альтернативы функцию можно указать встраиваемой в определении, расположенном вне тела класса:

inline // функцию можно указать встраиваемой в определении

Screen &Screen::move(pos r, pos с) {

 pos row = r * width; // вычислить положение ряда

 cursor = row + с;    // переместить курсор к столбцу этого ряда

 return *this;        // возвратить этот объект как l-значение

}

char Screen::get(pos r, pos с) const // объявить встраиваемый в классе

{

 pos row = r * width;      // вычислить положение ряда

 return contents[row + с]; // возвратить символ в данном столбце

}

Перейти на страницу:

Похожие книги