class CleverDog: public Dog { …
15. Добавить вызов новых методов к обработчику нажатия кнопки Call, как показано в листинге 5.6. Листинг 5.6
case IDC_BUTTON4:
MyDog->Speak();
MyDog->Add(10, 20);
MyDog->Mult(6, 7);
break;
16. Скомпилировать и запустить проект. Последовательное нажатие кнопок Create, Assign, Call и Destroy показывает, что вызов унаследованных и добавленных методов происходит одинаково успешно.
В классе CleverDog можно объявить конструктор и деструктор. В этом случае вызов конструкторов и деструкторов будет происходить в следующем порядке:
При создании:
? вызов конструктора Dog.
? вызов конструктора CleverDog.
При уничтожении:
? вызов деструктора CleverDog.
? вызов деструктора Dog.
Независимо от количества ступеней наследования при вызове конструкторов всегда действует правило «Последовательно вызываются конструкторы от базового класса, лежащего в основе иерархии, до текущего класса», а при вызове деструкторов все происходит в обратном порядке, сначала вызывается деструктор текущего класса, затем его базового класса и далее до класса, лежащего в основе иерархии.
Полиморфизм
Полиморфизм является способностью разных объектов выполнять одни и те же команды, но при этом каждый объект может поддерживать свой метод реализации полученной команды. Следующее упражнение проиллюстрирует применение полиморфизма в eVC.
Упражнение 5.1 (продолжение)
17. Добавить в файл DogClass.h еще один класс, как показано в листинге 5.7. Добавленный класс полностью идентичен классу CleverDog, за тем исключением, что новая собака путает сложение и умножение.
Листинг 5.7
class StupidDog: public Dog {
public:
void Add(int x, int y){
int i = x*y;
char mm[32];
wchar_t *szStr = L"";
wchar_t mstr[32];
sprintf(mm,"Результат сложения: %d\n", i);
mbstowcs(mstr, mm, 32);
szStr = mstr;
MessageBox(NULL, szStr, TEXT(«TUT»), 0);
};
void Mult(int x, int y){
int i = x+y;
char mm[32];
wchar_t *szStr = L"";
wchar_t mstr[32];
sprintf(mm,"Результат умножения: %d\n", i);
mbstowcs(mstr, mm, 32);
szStr = mstr;
MessageBox(NULL, szStr, TEXT(«TUT»), 0);
};
};
18. В конец класса Dog нужно дописать два новых объявления, как показано в листинге 5.8. Листинг 5.8
virtual void Add(int x, int y) = 0;
virtual void Mult(int x, int y) = 0;
19. В файле OOP1.cpp нужно заменить объявление переменных типа CleverDog объявлением массива объектных переменных типа Dog, как это показано в листинге 5.9. Листинг 5.9
// Global Variables:
HINSTANCE g_hInst;
HWND g_hwndCB;
Dog *Dogs[4];
20. Изменить код обработчиков нажатий кнопок, как показано в листинге 5.10. Листинг 5.10
int i;
case IDC_BUTTON1:
Dogs[0] = new CleverDog();
Dogs[1] = new StupidDog();
Dogs[2] = new CleverDog();
Dogs[3] = new StupidDog();
break;
case IDC_BUTTON2:
for(i = 0; i<4; i++) {
delete Dogs[i];
Dogs[i] = NULL;
}
break;
case IDC_BUTTON3:
Dogs[0]->age = 200;
break;
case IDC_BUTTON4:
for(i = 0; i<4; i++)
Dogs[i]->Mult(20, 10);
break;
21. Скомпилировать и запустить программу. Для проверки работы нужно последовательно нажать кнопки Create, Call и Destroy. После нажатия кнопки Call вы должны получить два сообщения с правильным ответом 200 и два сообщения с неправильным ответом 30.
В классах CleverDog и StupidDog есть методы с одинаковыми именами и сигнатурами. Правда, реализация этих методов отличается, так как объект StupidDog путает умножение и сложение.
Язык C++ позволяет производить «тихое» приведение типа объекта к типу базового класса. Именно это сделало возможным поместить все объекты CleverDog и StupidDog в один массив объектов типа Dog. Но изначально в классе Dog не было методов Add и Mult, и вызвать их инструкцией Dogs[i]->Mult() было невозможно. Чтобы исправить этот досадный недостаток, в классе Dog эти методы были объявлены. Но реализация этих методов отсутствует, так как она нужна только дочерним классам. Такие методы без реализации называются абстрактными методами, и класс, в котором есть хотя бы один абстрактный метод, тоже становится абстрактным. Абстрактный класс не может порождать объекты, зато он может гарантировать полиморфное поведение своих наследников. Чтобы при вызове в таком полиморфном стиле объект знал «свой» метод, метод должен быть объявлен как virtual (виртуальный), что и было сделано в рассматриваемом примере. Виртуальный метод сохраняет свою виртуальность далее по всей иерархии наследования.
Инкапсуляция
Поскольку принцип инкапсулирования говорит нам о сокрытии от внешнего мира деталей реализации класса (объекта) и о его независимом поведении, то в языке программирования для достижения этих целей должны существовать определенные технологии.
К подобным методикам можно отнести использование конструкторов и деструкторов. Эти методы позволяют подготовить объект к работе и осуществить «уборку рабочего места» к моменту, когда объект завершает свое существование.
Читать дальше
Конец ознакомительного отрывка
Купить книгу