6.3. Член функции на клас
Член функциите предлагат набор от операции, които потребителят може да изпълнява над типа клас. Този набор се нарича публичен интерфейс на класа. Дали класът е сполучлив или не зависи от сложността и ефективността на набора му от член функции. Този раздел разглежда член функциите, необходими на класа Screen. Той е разделен на следните четири подсекции: управляващи функции, функции за реализация, помощни функции и функции за достъп. Тези категории член функции не са част от езика С++. По-скоро те изразяват един метод за мислене относно типовете член функции, от които най-общо се нуждае един клас.
Управляващи функции
Един набор от специализирани член функции, управлявашите
функции, управляват обектите на класа, обработвайки инициализацията, присвояването, управлението на паметта и преобразуването на типовете. Управляващите функции обикновено се извикват неявно от компилатора.
Член функцията за инициализация, наречена конструктор, се извиква неявно всеки път, когато се дефинира обект клас или за него се отделя памет чрез оператора new. Един конструктор се дефинира като му се даде за име името на класа. Ето конструктора на класа Screen:
Screen::Screen( int high, int wid, char bkground )
{ // Screen initializer function: constructor
int sz = high * wid;
heigth = high;
width = wid;
cursor = screen = new char[ sz + 1 ];
char *ptr = screen;
char *endptr = screen + sz;
while ( ptr != endptr ) *ptr++ = bckground;
*ptr = ‘/0’; // end of screen marked by null
}
Декларацията на конструктора в тялото на Screen предлага подразбиращи се стойности за аргументите high, wid и bkground.
class Screen
{ public: Screen ( int = 8, int = 40; char=’#’ ); // ... };
Всеки деклариран обект от тип Screen автоматично се инициализира чрез конструктора на Screen. Например,
Screen s1; // Screen(8,40,’#’)
Screen *ps = new Screen( 20 ); // Scrren(20,40,’#’)
main()
{ Screen s(24,80,’*’); // Screen(24,80,’*’) // ... }
Глава 7 разглежда подробно конструкторите и другите управляващи функции.
Функции за реализация
Второто множество от член функции, наречени функции за реализация, предлагат възможности, отнасящи се до абстракцията клас. Например, от Screen се очаква да поддържа такива движения като home() и move(). Допълнителни изисквания към движението на курсора са forward(), back(), up() и down(). Член функците forward() и back() местят курсора по един символ. При достигане на края или началото на екрана курсорът се движи кръгово.
inline void Screen::forward()
{ // advance cursor one screen element
++cursor;
// check for bottom of screen; wrapround
// bottom of screen is null element
if ( *cursor == ‘�’ ) home();
}
inline void Screen::back()
{ // move cursor backward one screen element
// check for top of screen; wrapround
if ( cursor == screen ) bottom();
else—cursor; }
bottom() е от функциите за реализация и позиционира курсора в последната колона на екрана.
inline void Screen::bottom()
{
int sz = width*height - 1;
cursor = screen + sz; }
up() и down() местят курсоро нагоре и надолу по един ред от екрана. При достигане на най-горния и най-долния ред на екрана курсорът не се движи кръгово, а предизвиква издаване на звуков сигнал, оставайки там където се намира.
const char BELL = ‘�07’;
void inline Screen::up()
{ // move cursor up one row of screen
// do not wraparound; rather, ring bell
if ( row() == 1 ) // at top?
cout.put( BELL );
else cursor -= width; }
void inline Screen::down()
{ if ( row() = heigth ) // at bottom ?
cout.put( BELL ); else cursor += width; }
Упражнение 6-3. Към движенията на курсора могат да бъдат добавени движение напред и назад с по една дума, където думата е ограничена с интервали. Реализирайте wordForward().
Упражнение 6-4. Друга интересна възможност е курсорът да може да бъде позициониран при появата на даден низ. Например,
myScreen.find( "this” ); Реализирайте find( char* ).
Помощни функции
Друго множество от член функции се занимава с някои допълнителни задачи. Обикновено не се предвижда тези функции да бъдат викани директно от потребителя. По-скоро, те подпомагат работата на някои други член функции на класовете. Най-често те се декларират като лични. checkRange(), дефинирана по-рано, е една помощна фуннкция. Ето още четири такива функции.
row() връща реда, на който курсорът е позициониран:
inline Screen::row() { // return current row
int pos = cursor - screen + 1;
return (pos+width-1)/width; }
col() връща колоната, в която се намира курсорът:
inline Screen::col()
{ // return current column
int pos = cursor - screen + 1;
return ((pos+width-1) % width)+1;
}
remainingSpase() връща броя интервали, оставащи на екрана без да се брои текущата позиция:
inline Screen::remainingSpase()
{ // current position is no longer remaining
int sz = width*heigth;
return( screen + sz - cursor - 1 );
};
stats() показва информацията, връщана от трите предходни помощни функции; тя беше полезна при тестването на описаните тук части от програми.
void inline Screen::stats()
{
cout << "row: " << row() << "t";
cout << "col: " << col() << "t";
cout << "rm: " << remainingSpace() << "n";
}
Следва една малка програмка, която служи за упражняване на член функциите, реализирани до тук.
#include "Screen.C"
#include <stream.h>
main()
{ // exercise cursor movements
Screen x(3,3); int sz = x.getHeigth() * x.getWidth();
cout << "Screen Object ( " << x.getHeight() << ", " << x.Width() << " ) ( size: " << sz << " )nn";
x.home();
for ( int i = 0; i <= sz; ++i )
{ // "<= " in order to wrapround
x.stats();
x.forward();
}
return 0;
}
Когато тази програма бъде компилирана и изпълнена се получават следните резултати:
Screen Object ( 3, 3 ) ( size: 9 )
row: 1 col: 1 rm: 8
row: 1 col: 2 rm: 7
row: 1 col: 3 rm: 6
row: 2 col: 1 rm: 5
row: 2 col: 2 rm: 4
row: 2 col: 3 rm: 3
row: 3 col: 1 rm: 2
row: 3 col: 2 rm: 1
row: 3 col: 3 rm: 0
Функции за достъп
Скриването на информацията капсулира вътрешното представяне на обектите класове, и чрез това предпазва потребителя от внасяне на промени в това представяне. Също така важно е да бъде защитено вътрешното състояние на обекта клас от случайни програмни модификации. Едно специфично малко множество от функции предлага всичко, необходимо за достъп до обект за запис. Ако се получи грешка, областта за търсене се ограничава до това множество от функции, което значително улеснява решаването на проблемите, свързани поддържането и корекциите на програмите. Член функциите, осигуряващи достъпа на потребителя до данните на обектите се наричат функции за достъп. До сега разглеждахме само функции за достъп за четене. Ето две функции set(), които позволяват на потребителя да пише на екрана:
void Screen::set( char *s )
{ // write string begining at screen element
int space = remainingSpace();
int len = strlen( s );
if ( space < len )
{
cerr << "Screen: warning: truncaton: " << "space: " << space
<< "string length: " << len << "n"; len = space; }
for ( int i = 0; i < len; ++i )
*cursor++ = *s++; }
void Screen::set( char ch )
{ if ( ch == ‘�’ )
cerr << "Screen: warning: " << "null character (ignored).n";
else *cursor = ch; }
При реализацията на нашия клас Screen сме възприели eдно опростяващо допускане, че той не съдържа нулеви символи. Това е причината, поради която set() не разрешава нулевия символ да бъде изписан на екрана.
Функциите за достъп могат също така да обогатят класа чрез множество от предикатни операции. Класът Screen, например, може да бъде обогатен чрез набор от функции isEqual().
isEqual(char ch) връща истина ако ch е еднакъв със символа, намиращ се на текущата позиция на курсора. Ето реализацията й:
class Screen
{ public: isEqual( char ch )
{ return (ch == *cursor ); } // ... }
isEqual(char* s) връща истина ако масивът от символи, започващ от текущата позиция на курсора е еднакъв с s.
#include <string.h>
Screen::isEqual( char *s )
{ // yes? return 1; otherwise, 0
int len = strlen( s );
if ( remainingSpace() < len )
return 0;
char *p = cursor;
while ( len-- > 0 )
if ( *p++ != *s++ ) return 0;
return 1; }
isEqual(Screen&) връша истина ако два обекта Screen са еднакви; т.е. височината, ширината и съдържанието на двата екрана трябва да бъдат еднакви.
Screen::isEqual( Screen& s )
{ // first, are they phisically unequal?
if ( wigth != s.width || heigth != s.heigth )
return 0; // do both share the same screen?
char *p = screen;
char *q = s.screen;
if p == q return 1; // be careful not to walk off the Screens
while ( *p && *p++ == *q++ );
if ( *p ) // loop broke on not equal
return 0;
return 1; }