Закрытые и открытые функции-члены
Функцию-член можно объявить в любой из секций 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