Void main(). cout<<recode("Объем призмы ")<<ob1<<"\n";
{
double ob1,ob2;
V1 prizma;
V2 piramida;
ob1 = prizma.f2();
cout<<recode("Объем призмы ")<<ob1<<"\n";
ob2 = piramida.f2();
cout<<recode("Объем пирамиды ")<<ob2<<"\n";
}
char* recode(char *TXT)
{
static char buf[257];
strcpy(buf,TXT);
unsigned int i, kol;
kol = strlen(buf);
for(i=0;i<kol;i++)
{
if (buf[i]>='А'&&buf[i]<='п')buf[i]-=64;
if (buf[i]>='р'&&buf[i]<='я')buf[i]-=16;
}
return buf;
}
Так у класі V функція f2() є загальною і забезпечує повний інтерфейс введення та контролю даних. У ній надається можливість ввести довжину, ширину та висоту фігури, та якщо одне з введених значень буде менше або дорівнювати 0, користувачу надається можливість повторити введення даних.
Ця "велика" функція викликає "маленьку" віртуальну функцію, яка є чистою віртуальною функцію та поки що не виконує ніяких дій.
У похідному класі V1 виконується реалізація віртуальної функції f1() базового класу, яка повертає об’єм призми, розрахований як x*y*z.
У похідному класі V2, який спадкується від класу V1, демонструється доповнення віртуальної функції f1() відносно класу V1. При реалізації даної функції об’єм піраміди розраховується як 1/3 частини об’єму призми:
return 1./3*V1::f1();
У функції реалізації програми main() створюємо два об’єкти prizma класу V1 та piramida класу V2. Після цього визиваємо лише одну функцію базового класу f2(), яка забезпечує загальний інтерфейс введення даних та визиває функцію пошуку об’єму f1(), яка є віртуальною. Таким чином, за адресою будуть виконуватись віртуальні функції похідних класів, відповідно V1 та V2 у яких і будуть розраховуватися об’єми відповідних фігур.
Результат виконання програми буде виглядати наступним чином:
Введите длину основания фигуры 3
Введите ширину основания фигуры 4
Введите высоту фигуры 5
Объем призмы 60
Введите длину основания фигуры 3
Введите ширину основания фигуры 4
Введите высоту фигуры 5
Объем пирамиды 20
4.4. Внутрішнє представлення об’єктів і таблиця методів
Для кожного класу, що містить хоч би один віртуальний метод, компілятор створює таблицю віртуальних методів (vtbl), в якій для кожного віртуального методу записана його адреса в пам'яті. Адреси методів містяться в таблиці в порядку їх опису в класах. Адреса будь-якого віртуального методу має в vtbl один і той же зсув для кожного класу в межах ієрархії.
Кожен об'єкт містить приховане додаткове поле посилання на vtb1, зване vptr. Воно заповнюється конструктором при створенні об'єкту (для цього компілятор додає в початок тіла конструктора відповідні інструкції). На етапі компіляції посилання на віртуальні методи замінюються на звернення до vtbl через vptr об'єкту, а на етапі виконання у момент звернення до методу його адреса вибирається з таблиці. Таким чином, виклик віртуального методу, на відміну від звичайних методів і функцій, виконується через додатковий етап отримання адреси методу з таблиці. Це декілька уповільнює виконання програми.
Рекомендується робити віртуальними деструктори для того, щоб гарантувати правильне звільнення пам'яті з-під динамічного об'єкту, оскільки в цьому випадку у будь-який момент часу буде вибраний деструктор, відповідний фактичному типу об'єкту. Деструктор передає операції delete розмір об'єкту, що має тип size_t. Якщо об'єкт, що видаляється, є похідним і в ньому не визначений віртуальний деструктор, розмір об'єкту, який передається, може виявитися неправильним.
Чіткого правила, по якому метод слід робити віртуальним, не існує. Можна тільки дати рекомендацію оголошувати віртуальними методи, для яких є вірогідність, що вони будуть перевизначені в похідних класах. Методи, які у всій ієрархії залишаться незмінними або ті, якими похідні класи користуватися не будуть, робити віртуальними немає сенсу. З іншого боку, при проектуванні ієрархії не завжди можна передбачити, яким чином розширюватимуться базові класи (особливо при проектуванні бібліотек класів), а оголошення методу віртуальним забезпечує гнучкість і можливість розширення.
Для пояснення останньої тези уявимо собі, що виклик методу draw здійснюється з методу переміщення об'єкту. Якщо текст методу переміщення не залежить від типу переміщуваного об'єкту (оскільки принцип переміщення всіх об'єктів однаковий, а для малювання викликається конкретний метод), перевизначати цей метод в похідних класах немає необхідності, і він може бути описаний як невіртуальний. Якщо метод draw віртуальний, метод переміщення зможе без перекомпіляції працювати з об'єктами будь-яких похідних класів – навіть тих, про які при його написанні нічого відомо не було.
Віртуальний механізм працює тільки при використанні вказівок або посилань на об'єкти. Об'єкт, що визначений через вказівку або посилання і містить віртуальні методи, називається поліморфним. В даному випадку поліморфізм полягає в тому, що за допомогою одного і того ж звернення до методу виконуються різні дії залежно від типу, на який посилається вказівка в кожен момент часу.
Розглянемо приклад спільного використання віртуальних і невіртуальних функцій та розміщення об'єктів в пам’яті:
#include <iostream>
using namespace std;
Дата добавления: 2014-12-26; просмотров: 765;