Анимация
JavaScript


Главная  Библионтека 

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 [ 61 ] 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76

char buf[80]; /* = */

win->GetWindowText(buf, sizeof(buf)); ...

Так как я должен выполнить инициализацию при помощи явного вызова функции, то умышленно нарушаю свое правило "один оператор в строке" для того, чтобы, по крайней мере, вместить объявление и инициализацию в одной и той же строке.

Здесь имеется несколько проблем, первая из которых заключается в плохом проектировании класса CWnd (представляющем окно). Так как у окна есть " текстовый" атрибут, хранящий заголовок, то вы должны иметь возможность доступа к этому атрибуту подобным образом:

CString caption = win->caption();

и вы должны иметь возможность модифицировать этот атрибут так:

win->caption() = " новое содержание";

но вы не можете сделать этого в текущей реализации. Главная проблема состоит в том, библиотека MFC не была спроектирована в объектно-ориентированном духе - т. е. начать с объектов, затем выбрать, какие

static int have been called = 0; if( !have been called )

have been called = 1; do one time initializations();

134. Избегайте инициализации в два приема

1 35. Суперобложки на Си++ для существующих интерфейсов редко хорошо работают

Как правило, переменная должна инициализироваться во время объявления. Разделение инициализации и объявления иногда обусловливается плохим проектированием в программе, которая написана не вами, как в следующем фрагменте, написанном для выполнения совместно с библиотекой MFC Microsoft:

f( CWnd *win ) CWnd - это окно

Следующая строка загружает "буфер" с шапкой окна (текстом в строке заголовка)



сообщения передавать между ними и какими атрибутами их наделить. Вместо этого проектировщики Microsoft начали от существующего процедурного интерфейса (API Си - интерфейса прикладного программирования для Windows на Си) и добавили к нему суперобложку на Си++, тем самым увековечив все проблемы существующего интерфейса. Так как в API Си была функция с именем GetWindowText(), то проектировщики беззаботно сымитировали такой вызов при помощи функции-члена в своей оболочке CWnd. Они поставили заплату на интерфейс при помощи следующего вызова:

CString str;

win->GetWindowText( str );

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

Главный урок состоит в том, что проекты, основанные на процедурном подходе, радикально отличаются от объектно-ориентированных проектов. Обычно невозможно использовать код из одного проекта в другом без большой переработки. Простая оболочка из классов Си++ вокруг процедурного проекта не сделает его объектно-ориентированным.

Поучительно, я думаю, пошарить вокруг в поисках решения текущей проблемы с помощью Си++, но предупреждаю вас - здесь нет хорошего решения (кроме перепроектирования библиотеки классов). Моя первая попытка сделать оболочку вокруг CWnd показана на листинге 11.

Для обеспечения возможности win->text() = "Новый заголовок" необходим вспомогательный класс (window::caption). Вызов text() возвращает объект заголовка, которому затем передается сообщение присваиванием.

Главная проблема на листинге 11 заключается в том, что библиотека MFC имеет много классов, унаследованных от CWnd, и интерфейс, реализованный в классе window, не будет отражен в других потомках CWnd. Си++ является компилируемым языком, поэтому нет возможности вставлять класс в середину иерархии классов без изменения исходного кода.

Листинг 1 2 определяет другое решение для смеси Си++ с MFC. Я выделил класс window::caption в отдельный класс, который присоединяется к окну, когда оно инициализируется. Используется подобным образом:

f(CWnd *win)

caption cap( win )

CString s = cap; поддерживается преобразование в CString.



cap="Новый заголовок"; использует операцию

operator=(CString&)

Мне не нравится то, что изменение заголовка caption меняет также окно, к которому этот заголовок присоединен в этом последнем примере. Скрытая связь между двумя объектами может сама по себе быть источником недоразумений, будучи слишком похожей на побочный эффект макроса. Как бы то ни было, листинг 1 2 решает проблему инициализации.

Листинг 11. Обертка для CWnd: первая попытка

I class window : public CWnd 2{

3 public:

4 class caption 5{

6 CWnd *target window;

8 private: friend class window;

9 caption( CWnd *p ) : target window(p) {}

II public:

12 operator CString ( void ) const;

13 const caption &operator=( const CString &s );

14 };

16 caption text( void );

17 };

18 --------------------------------------------------------19 caption window::text( void )

20 {

21 return caption( this );

22 }

23 --------------------------------------------------------24 window::caption:: operator CString( void ) const

25 {

26 CString output;

27 target window->GetWindowText( output );

28 return output; возвращает копию

29 }

30 --------------------------------------------------------31 const caption &window::caption::operator=(const CString &s)

32 {

33 target window->SetWindowText( s );

34 return * this;

35 }



0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 [ 61 ] 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76