Программирование >>  Решение нетривиальных задач 

1 ... 46 47 48 [ 49 ] 50 51 52 ... 77


string s;

char array[128];

s.buf = array;

и организация памяти разрушается, когда эта строка покидает область действия.

Простое закрытие при помощи модификатора private поля buf не помогает, если вы продолжаете обеспечивать доступ посредством функции. Листинг 7 показывает фрагмент простого определения строки, которое будет использоваться мной несколько раз в оставшейся части этой главы. (Упрощение, сделанное мной, свелось к помещению всего в один листинг; обычно определение класса и встроенные функции будут в заголовочном файле, а остальной код - в файле .cpp).

Листинг 7. Простой строковый класс

1 class string

3 char *buf;

4 int length; длина буфера (не строки); 5

6 public:

7 virtual

8 ~string( void );

9 string( const char *input str = );

10 string( const string &r );

12 virtual const string &operator=( const string &r );

14 virtual int operator< ( const string &r ) const;

15 virtual int operator> ( const string &r ) const;

16 virtual int operator==( const string &r ) const;

18 virtual void print( ostream &output ) const;

19 ...

20 };

21 ----------------------------------------------------------------22 inline string::string( const char *input str /*= */ )

23 {

24 length = strlen(input str) + 1;

25 buf = new char[ length ];

26 strcpy( buf, input str );

27 }

28 ----------------------------------------------------------------29 inline string::string( const string &r )

30 {

31 length = r.length;

32 buf = new char[ length ];

33 strcpy( buf, r.buf );

34 }

35 ----------------------------------------------------------------36 /* виртуальн1й */ string:: ~string( void )

37 {



виртуальн1й */ int

string:

: operator< ( const string

&r ) const

return strcmp(buf,

r.buf)

< 0;

виртуальн1й */ int

string:

:operator> ( const string

&r ) const

return strcmp(buf,

r.buf)

> 0;

виртуальн1й */ int

string:

: operator==( const string

&r ) const

return strcmp(buf,

r.buf)

== 0;

виртуальн1й */ void

string

::print( ostream &output )

const

cout << buf;

63 { 64

65 }

66

67 /*

68 { 69

70 }

71

73 { 74

75 }

76 77 inline ostream &operator<<( ostream &output, const string &s )

78 {

79 Эта функция не является функцией-членом класса string, 8 0 но не должна быть дружественной, потому что мной тут 81 реализован метод вывода строкой своего значения.

83 s.print(output);

84 return output;

85 }

Вы заметите, что я умышленно не реализовал следующую функцию в листинге 7:

string::operator const char*() { return buf; }

Если бы реализовал, то мог бы сделать следующее:

з delete buf;

39 }

40 ----------------------------------------------------------------41 /* виртуальн1й */ const string &string::operator=( const string &r)

42 {

43 if( this != &r )

44 {

45 if( length != r.length )

46 {

47 free( buf );

4 8 length = r.length;

4 9 buf = new char[ length ];

50 }

51 strcpy( buf, r.buf );

52 }

53 return *this;

54 } 55

56 57 /*

58 { 59

60 }

61



Операция приведения вызывает функцию operator const char* возвращающую buf. Тем не менее, деструктор класса string передает этот буфер оператору delete, когда строка покидает область действия. Следовательно, функция g() возвращает указатель на освобожденную память. В отличие от предыдущего примера, при этой второй проблеме нет закрученного оператора приведения в два этапа, намекающего нам, что что-то не так.

Реализация в листинге 7 исправляет это, заменив преобразование

void f( void )

string s;

...

printf( %s\n , (const char*)s );

но я не смогу реализовать функцию operator char*(), которая бы работала со строкой Unicode, использующей для символа 16-бит. Я должен бы был написать функцию operator wchar t*(), тем самым модифицировав код в функции f():

printf( %s/n , (const wchar t*)s );

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

Также есть проблемы со стороны внутренней согласованности. Имея указатель на buf, возвращенный функцией operator const char*(), вы все же можете модифицировать строку при помощи указателя и испортить поле length, хотя для этого вам придется немного постараться:

string s;

...

char *p = (char *)(const char *)s;

gets( p );

В равной степени серьезная, но труднее обнаруживаемая проблема возникает в следующем коде:

const char *g( void )

string s;

...

return (const char *)s;



1 ... 46 47 48 [ 49 ] 50 51 52 ... 77

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика