Закрытые и открытые функции-члены
Функцию-член можно объявить в любой из секций public, private или protected
тела класса. Где именно это следует делать? Открытая функция-член задает операцию, которая может понадобиться пользователю. Множество открытых функций-членов составляет интерфейс
класса. Например, функции-члены home(), move() и get() класса Screen
определяют операции, с помощью которых программа манипулирует объектами этого типа.
Поскольку мы прячем от пользователей внутреннее представление класса, объявляя его члены закрытыми, то для манипуляции объектами типа Screen необходимо предоставить открытые функции-члены. Такой прием– сокрытие информации – защищает написанный пользователем код от изменений во внутреннем представлении.
Внутреннее состояние объекта класса также защищено от случайных изменений. Все модификации объекта производятся с помощью небольшого набора функций, что существенно облегчает сопровождение и доказательство правильности программы.
До сих пор мы встречались лишь с функциями, поддерживающими доступ к закрытым членам только для чтения. Ниже приведены две функции set(), позволяющие пользователю модифицировать объект Screen. Добавим их объявления в тело класса:
class Screen { public: void set( const string &s ); void set( char ch ); // объявления других функций-членов не изменяются |
};
Далее следуют определения функций:
void Screen::set( const string &s ) { // писать в строку, начиная с текущей позиции курсора int space = remainingSpace(); int len = s.size(); if ( space < len ) { cerr << "Screen: warning: truncation: " << "space: " << space << "string length: " << len << endl; len = space; } _screen.replace( _cursor, len, s ); _cursor += len - 1; } void Screen::set( char ch ) { if ( ch == '\0' ) cerr << "Screen: warning: " << "null character (ignored).\n"; else _screen[_cursor] = ch; |
}
В реализации класса Screen мы предполагаем, что объект Screen не содержит двоичных нулей. По этой причине set() не позволяет записать на экран нуль.
Представленные до сих пор функции-члены были открытыми, их можно вызывать из любого места программы, а закрытые вызываются только из других функций-членов (или друзей) класса, но не из программы, обеспечивая поддержку другим операциям в реализации абстракции класса. Примером может служить функция-член remainingSpace
класса Screen(), использованная в set(const string&).
class Screen { public: // объявления других функций-членов не изменяются private: inline int remainingSpace(); |
remainingSpace()
сообщает, сколько места осталось на экране:
inline int Screen::remainingSpace() { int sz = _width * _height; return ( sz - _cursor ); |
(Детально защищенные функции-члены будут рассмотрены в главе 17.)
Следующая программа предназначена для тестирования описанных к настоящему моменту функций-членов:
#include "Screen.h" #include <iostream> int main() { Screen sobj(3,3); // конструктор определен в разделе 13.3.4 string init("abcdefghi"); cout << "Screen Object ( " << sobj.height() << ", " << sobj.width() << " )\n\n"; // Задать содержимое экрана string::size_type initpos = 0; for ( int ix = 1; ix <= sobj.width(); ++ix ) for ( int iy = 1; iy <= sobj.height(); ++iy ) { sobj.move( ix, iy ); sobj.set( init[ initpos++ ] ); } // Напечатать содержимое экрана for ( int ix = 1; ix <= sobj.width(); ++ix ) { for ( int iy = 1; iy <= sobj.height(); ++iy ) cout << sobj.get( ix, iy ); cout << "\n"; } return 0; |
Откомпилировав и запустив эту программу, мы получим следующее:
Screen Object ( 3, 3 )
abc
def
ghi