Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Липпман.doc
Скачиваний:
12
Добавлен:
14.08.2019
Размер:
7.54 Mб
Скачать

13.3.2. Доступ к членам класса

Говорят, что определение функции-члена принадлежит области видимости класса независимо от того, находится ли оно вне или внутри его тела. Отсюда следуют два вывода:

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

  • когда функция-член обращается к членам класса, операторы доступа “точка” и “стрелка” не необходимы.

Например:

#include <string>

void Screen::copy( const Screen &sobj )

{

// если этот объект и объект sobj - одно и то же,

// копирование излишне

// мы анализируем указатель this (см. раздел 13.4)

if ( this != &sobj )

{

_height = sobj._height;

_width = sobj._width;

_cursor = 0;

// создаем новую строку;

// ее содержимое такое же, как sobj._screen

_screen = sobj._screen;

}


}

Хотя _screen, _height, _width и _cursor являются закрытыми членами класса Screen, функция-член copy() работает с ними напрямую. Если при обращении к члену отсутствует оператор доступа, то считается, что речь идет о члене того класса, для которого функция-член вызвана. Если вызвать copy() следующим образом:

#include "Screen.h"

int main()

{

Screen s1;

// Установить s1

Screen s2;

s2.copy(s1);

// ...


}

то параметр sobj внутри определения copy() соотносится с объектом s1 из функции main(). Функция-член copy() вызвана для объекта s2, стоящего перед оператором “точка”. Для такого вызова члены _screen, _height, _width и _cursor, при обращении к которым внутри определения этой функции нет оператора доступа, – это члены объекта s2. В следующем разделе мы рассмотрим доступ к членам класса внутри определения функции-члена более подробно и, в частности, покажем, как для поддержки такого доступа применяется указатель this.

13.3.3. Закрытые и открытые функции-члены

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