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

We use cookies. Read the Privacy and Cookie Policy

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

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

class Screen {

public:

void home() { _cursor = 0; }

char get() { return _screen[_cursor]; }

char get( int, int );

void move( int, int );

bool checkRange( int, int );

int height() { return _height; }

int width() { return _width; }

// ...

};

Хотя у любого объекта класса есть собственная копия всех данных-членов, каждая функция-член существует в единственном экземпляре:

Screen myScreen, groupScreen;

myScreen.home();

groupScreen.home();

При вызове функции home() для объекта myScreen происходит обращение к его члену _cursor. Когда же эта функция вызывается для объекта groupScreen, то она обращается к члену _cursor именно этого объекта, причем сама функция home() одна и та же. Как же может одна функция-член обращаться к данным-членам разных объектов? Для этого применяется указатель this, рассматриваемый в следующем разделе.

13.3.1. Когда использовать встроенные функции-члены

Обратите внимание, что определения функций home(), get(), height() и width() приведены прямо в теле класса. Такие функции называются встроенными. (Мы говорили об этом в разделе 7.6.)

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

class Screen {

public:

// использование ключевого слова inline

// для объявления встроенных функций-членов

inline void home() { _cursor = 0; }

inline char get() { return _screen[_cursor]; }

// ...

};

Определения home() и get() в приведенных примерах эквивалентны. Поскольку ключевое слово inline избыточно, мы в этой книге не пишем его явно для функций-членов, определенных в теле класса.

Функции-члены, состоящие из двух или более строк, лучше определять вне тела. Для идентификации функции как члена некоторого класса требуется специальный синтаксис объявления: имя функции должно быть квалифицировано именем ее класса. Вот как выглядит определение функции checkRange(), квалифицированное именем Screen:

#include iostream

#include "screen.h"

// имя функции-члена квалифицировано именем Screen::

bool Screen::checkRange( int row, int col )

{ // проверить корректность координат

if ( row 1 || row _height ||

col 1 || col _width ) {

cerr "Screen coordinates ( "

row ", " col

" ) out of bounds. ";

return false;

}

return true;

}

Прежде чем определять функцию-член вне тела класса, необходимо объявить ее внутри тела, обеспечив ее видимость. Например, если бы перед определением функции checkRange() не был включен заголовочный файл Screen.h, то компилятор выдал бы сообщение об ошибке. Тело класса определяет полный список его членов. Этот список не может быть расширен после закрытия тела.

Обычно функции-члены, определенные вне тела класса, не делают встроенными. Но объявить такую функцию встроенной можно, если явно добавить слово inline в объявление функции внутри тела класса или в ее определение вне тела, либо сделав то и другое одновременно. В следующем примере move() определена как встроенная функция-член класса Screen:

inline void Screen::move( int r, int c )

{ // переместить курсор в абсолютную позицию

if ( checkRange( r, c ) ) // позиция на экране задана корректно?

{

int row = (r-1) * _width; // смещение начала строки

_cursor = row + c - 1;

}

}

Функция get(int, int) объявляется встроенной с помощью слова inline:

class Screen {

public:

inline char get( int, int );

// объявления других функций-членов не изменяются

};

Определение функции следует после объявления класса. При этом слово inline можно опустить:

char Screen::get( int r, int c )

{

move( r, c ); // устанавливаем _cursor

return get(); // вызываем другую функцию-член get()

}

Так как встроенные функции-члены должны быть определены в каждом исходном файле, где они вызываются, то встроенную функцию, не определенную в теле класса, следует поместить в тот же заголовочный файл, в котором определен ее класс. Например, представленные ранее определения move() и get() должны находиться в заголовочном файле Screen.h после определения класса Screen.