Шаг 124.
Оптимизация кода: объектно-ориентированное программирование

    На этом шаге мы рассмотрим представление объектно-ориентированной программы.

    Объектно-ориентированное программирование в значительной степени усложняет получаемый исполняемый код. Рассмотрим один простой пример. В следующем листинге представлена программа на C++.

#include <stdio.h>
#include <string.h>
#include <conio.h>
class stroka {
  public:
	 char c[200];
	 char g[100];
	 stroka() {strcpy(g,"Privet");}
	 int strcp();
};

stroka::strcp()
{
  strcpy(c,g);
  return 0;
}

void main()
{
  stroka *s = new stroka;
  s->strcp();
  printf("%s\n",s->c);
  delete s;
  getch();
}
Текст этой программы можно взять здесь.

    Ниже представлен дизассемблированный код функции main.

CODE:0041008E _main           proc near               ; DATA XREF: DATA:00420044o
CODE:0041008E 
CODE:0041008E var_24          = dword ptr -24h
CODE:0041008E var_14          = word ptr -14h
CODE:0041008E dest            = dword ptr -4
CODE:0041008E argc            = dword ptr  8
CODE:0041008E argv            = dword ptr  0Ch
CODE:0041008E envp            = dword ptr  10h
CODE:0041008E 
CODE:0041008E                 push    ebp
CODE:0041008F                 mov     ebp, esp
CODE:00410091                 add     esp, 0FFFFFFDCh
CODE:00410094                 push    ebx
CODE:00410095                 mov     eax, offset unk_420080
CODE:0041009A                 call    @__InitExceptBlock
CODE:0041009F                 push    12Ch
CODE:004100A4                 call    @$bnew$qui      ; operator new(uint)
CODE:004100A9                 pop     ecx
CODE:004100AA                 mov     [ebp+dest], eax
CODE:004100AD                 test    eax, eax
CODE:004100AF                 jz      short loc_4100D8
CODE:004100B1                 mov     [ebp+var_14], 14h
CODE:004100B7                 push    offset aPrivet  ; src
CODE:004100BC                 mov     eax, [ebp+dest]
CODE:004100BF                 add     eax, 0C8h
CODE:004100C4                 push    eax             ; dest
CODE:004100C5                 call    _strcpy
CODE:004100CA                 add     esp, 8
CODE:004100CD                 mov     [ebp+var_14], 8
CODE:004100D3                 mov     ebx, [ebp+dest]
CODE:004100D6                 jmp     short loc_4100DB
CODE:004100D8 ; ------------------------------------------------------------
CODE:004100D8 
CODE:004100D8 loc_4100D8:                             ; CODE XREF: _main+21j
CODE:004100D8                 mov     ebx, [ebp+dest]
CODE:004100DB 
CODE:004100DB loc_4100DB:                             ; CODE XREF: _main+48j
CODE:004100DB                 push    ebx             ; dest
CODE:004100DC                 call    sub_410074
CODE:004100E1                 pop     ecx
CODE:004100E2                 push    ebx
CODE:004100E3                 push    offset aS       ; format
CODE:004100E8                 call    _printf
CODE:004100ED                 add     esp, 8
CODE:004100F0                 push    ebx
CODE:004100F1                 call    @$bdele$qpv     ; operator delete(void *)
CODE:004100F6                 pop     ecx
CODE:004100F7                 call    _getch
CODE:004100FC                 mov     eax, [ebp+var_24]
CODE:004100FF                 mov     large fs:0, eax
CODE:00410105                 pop     ebx
CODE:00410106                 mov     esp, ebp
CODE:00410108                 pop     ebp
CODE:00410109                 retn
CODE:00410109 _main           endp

    Как видите, получившийся код достаточно сложен. Мы ее будем проводить его детальный анализ, т.к. в этом случае нам пришлось бы включать в него и анализ библиотечных программ. Остановимся только на некоторых ключевых моментах.

    Оператор new сводится к выполнению библиотечной процедуры: @$bnew$qui. Она выделяет память для свойств экземпляра объекта (300 байт = 12CH).

    Конструктор хранится и выполняется непосредственно в теле программы. Это связано с тем, что и сам конструктор определен в тексте класса. Для эксперимента попробуйте вынести текст конструктора в отдельную функцию, и вы увидите, что конструктор будет вызываться из main, как обычная функция.

    Процедуру @__InitExceptBlock вставляет транслятор для поддержки обработки исключений (Exception). Вы можете удалить информацию, необходимую для обработки исключений, тем самым несколько сократив размер исполняемой программы, но тогда вы не сможете использовать операторы исключений, такие как try или catch.

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

    Приведем теперь фрагмент той же дизассемблированной программы, но с использованием опции , что для транслятора Borland C++ означает - не поддерживать обработку исключений. Как видите, текст программы оказался значительно проще.

CODE:0041008E _main           proc near               ; DATA XREF: DATA:00420044o
CODE:0041008E 
CODE:0041008E argc            = dword ptr  8
CODE:0041008E argv            = dword ptr  0Ch
CODE:0041008E envp            = dword ptr  10h
CODE:0041008E 
CODE:0041008E                 push    ebp
CODE:0041008F                 mov     ebp, esp
CODE:00410091                 push    ebx
CODE:00410092                 push    12Ch
CODE:00410097                 call    @$bnew$qui      ; operator new(uint)
CODE:0041009C                 pop     ecx
CODE:0041009D                 mov     ebx, eax
CODE:0041009F                 test    ebx, ebx
CODE:004100A1                 jz      short loc_4100BB
CODE:004100A3                 push    offset aPrivet  ; src
CODE:004100A8                 lea     eax, [ebx+0C8h]
CODE:004100AE                 push    eax             ; dest
CODE:004100AF                 call    _strcpy
CODE:004100B4                 add     esp, 8
CODE:004100B7                 mov     eax, ebx
CODE:004100B9                 jmp     short loc_4100BD
CODE:004100BB ; ------------------------------------------------------------
CODE:004100BB 
CODE:004100BB loc_4100BB:                             ; CODE XREF: _main+13j
CODE:004100BB                 mov     eax, ebx
CODE:004100BD 
CODE:004100BD loc_4100BD:                             ; CODE XREF: _main+2Bj
CODE:004100BD                 mov     ebx, eax
CODE:004100BF                 push    ebx             ; dest
CODE:004100C0                 call    sub_410074
CODE:004100C5                 pop     ecx
CODE:004100C6                 push    ebx
CODE:004100C7                 push    offset aS       ; format
CODE:004100CC                 call    _printf
CODE:004100D1                 add     esp, 8
CODE:004100D4                 push    ebx
CODE:004100D5                 call    @$bdele$qpv     ; operator delete(void *)
CODE:004100DA                 pop     ecx
CODE:004100DB                 call    _getch
CODE:004100E0                 pop     ebx
CODE:004100E1                 pop     ebp
CODE:004100E2                 retn
CODE:004100E2 _main           endp

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




Предыдущий шаг Содержание Следующий шаг