русс | укр

Языки программирования

ПаскальСиАссемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование

Все о программировании


Linux Unix Алгоритмические языки Аналоговые и гибридные вычислительные устройства Архитектура микроконтроллеров Введение в разработку распределенных информационных систем Введение в численные методы Дискретная математика Информационное обслуживание пользователей Информация и моделирование в управлении производством Компьютерная графика Математическое и компьютерное моделирование Моделирование Нейрокомпьютеры Проектирование программ диагностики компьютерных систем и сетей Проектирование системных программ Системы счисления Теория статистики Теория оптимизации Уроки AutoCAD 3D Уроки базы данных Access Уроки Orcad Цифровые автоматы Шпаргалки по компьютеру Шпаргалки по программированию Экспертные системы Элементы теории информации

Виртуальные функции


Дата добавления: 2015-07-09; просмотров: 1080; Нарушение авторских прав


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

Указателем, обращающимся к таблице, является указатель на базовый класс. Его значением может быть адрес объекта любого класса иерархии.

Очень часто класс, содержащей виртуальный метод, называют полиморфным классом. Главная особенность заключается в том, что полиморфные классы допускают обработку объектов, тип которых неизвестен во время компиляции. Если в производном классе виртуальный метод не будет переопределен, то при вызове будет найден метод с таким именем вверх по иерархии классов (т.е. в базовом классе). Схема использования виртуальных функций приведена ниже.

class Based {

public:

virtual int fb(){return 0;}

//При наличии в классе виртуальных функций необходим виртуальный деструктор

virtual ~Based(){}

};

class Derived1:public Based {

public:

int fb() {return 5;}

~Derived1(){}

};

class Derived2:public Based {

int fb() {return 7;}

~Derived2(){}

};

class Derived3:public Based {

// fb не определена

};

 

void main()

{

Derived1 d1;

cout<< d1.fb(); //Позднее связывание не работает

//Правильный вызов

Based *pb=0;

pb=new Derived1;

cout<<pb->fb(); // возвращает 5



delete pb;

pb=new Derived2;

cout<<pb->fb(); // возвращает 7

delete pb;

pb=new Derived3;

cout<<pb->fb(); // возвращает 0

if(pb) delete pb;

}

В лабораторной работе для изучения механизма работы виртуальных функций используется идея паттерна проектирования программ под названием «Фабричный метод» (Faсtory Method) [3]. Паттерн используется в тех случаях, когда выбор класса, объект которого надо создавать, делается в процессе выполнения программы.

Здесь он применяется в программе, работающей с объектами двух разных классов T1 и T2, которые являются производными классами одного базового класса Shape.

Производные классы должны создавать плоские объекты следующих типов: квадрат, треугольник, прямоугольник, параллелограмм, трапеция, правильный шестиугольник, правильный восьмиугольник (square, triangle, rectangle, parallelogram, trapeze, hexagon, octagon). Для каждого типа фигуры вычисляются площадь, центр тяжести, радиусы вписанных или описанных окружностей и другие атрибуты [5], а также должны быть предусмотрены виртуальные методы Вращения (Rotate) и Перемещения (Move).

Операции над объектами этих классов могут быть такими (функции с 2-мя аргументами Shape* obj1, Shape* obj2):

- сравнить два объекта по площади - Compare;

- определить факт пересечения объектов – IsIntersect;

- определить факт включения одного объекта в другой – IsInclude.

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

Ниже приводится рекомендуемый вариант программы (упрощенный). В ней из трех фигур выбираются и обрабатываются две – объекты Triangle и Rectangle.

#include "stdafx.h"

#include <iostream>

using namespace std;

class Point{

public:int x,y;

};

class Shape { // Абстрактный базовый класс

public:

Point *arc;

char ID;

/* Поля и методы */

virtual int GetArea()=0;//Вычисление площади фигуры

virtual void CreateShape()=0;

virtual ~Shape(){}

};

class Rectangle : public Shape {

public:

void CreateShape(){cout<<"Input Rectangle coordinate points "<<endl;

cin>>arc[0].x; /*вводим все координаты*/}

/* методы*/

int GetArea(){ /*вычисление конкретной площади*/return 4;}

Rectangle (){arc=new Point[4]; ID='R';}

~Rectangle(){delete[] arc;}

};

class Triangle : public Shape {

public:

Triangle (){arc=new Point[3]; ID='T';}

void CreateShape(){cout<<"Input Triangle coordinate points"<<endl;

cin>>arc[0].x; /*вводим все координаты*/}

/*.....*/

int GetArea(){/*вычисление конкретной площади*/return 3;}

~Triangle(){delete[] arc;}

};

class Octagon : public Shape {

public:

Octagon(){arc=new Point[8]; ID='O';}

void CreateShape(){/*...*/}

/* .....*/

int GetArea(){/*вычисление конкретной площади*/return 8;};

~Octagon(){delete[] arc;}

};

class Operation

{ //Класс, инкапсулирующий методы обработки объектов классов

public:

void Compare(Shape* s1, Shape* s2)

{// Проверка правильности подбора типов фигур

if ((s1->ID=='T' && s2->ID=='R')||(s2->ID=='T' && s1->ID=='R'))

cout<<"Correct choice"<<endl;

else {cout<<"Not such operation"<<endl; return;}

//Вычисления

if (s1->GetArea()>=s2->GetArea()) cout<<"Area "<<s1->ID<<" >= "<<s2->ID<<endl;

else cout<<"Area "<<s1->ID<<" < "<<s2->ID<<endl;

}

void IsInclude(Shape* s1, Shape* s2)

{/* */}

void IsIntersect(Shape* s1, Shape* s2)

{/* */}

};

 

class FactoryShape{// Класс–фабрика объектов, производных от Shape

public:

Shape* generator()

{ switch(rand() % 3) {

case 0:

return new Triangle;

case 1:

return new Rectangle;

case 2:

return new Octagon;

}

}

};

 

int _tmain(int argc, _TCHAR* argv[])

{

//Создаем 2 указателя на базовый класс

Shape *p1=0,*p2=0;

//Создаем заданные объекты

FactoryShape f;

cout<<"Input 1-t shape"<<endl;

char cond='y';

while (cond=='y')

{

if (p1) delete p1;

p1=f.generator();

cout<<p1->ID<<endl;

cout<<"Continue choice?(y/…)"<<endl;

cin>>cond;

}

p1->CreateShape();

cout<<"Input 2-d shape"<<endl;

cond='y';

while (cond=='y')

{if (p2) delete p2;

p2=f.generator();

cout<<p2->ID<<endl;

cout<<"Continue choice? (y/…)"<<endl;

cin>>cond;

}

p2->CreateShape();

Operation op;

op.Compare(p1,p2); //Сравниваем площади

 

if(p1) delete p1;

if(p2) delete p2;

 

return 0;

}

Замечание. Можно для идентификации класса текущего объекта воспользоваться библиотекой typeinfo (#include <typeinfo>) и его компонентой typeid. Название класса выводится

typeid(*p).name(), где p=указатель на базовый класс.

 

Итак, конкретное задание подразумевает создание фабрики объектов для всех 7 фигур, выбором 2-х из них согласно заданию и написание для них функций класса Operation.

В этой работе я не требую вводить какие-либо классы для упрощения main, так как главное в ней – разобраться с механизмом вызова виртуальных функций.

 

Варианты заданий

Варианты заданий приведены в следующей таблице:

№ T1 T2

1. Треугольник Квадрат

2. Треугольник Прямоугольник

3. Треугольник Параллелограмм

4. Треугольник Трапеция

5. Треугольник Шестиугольник

6. Треугольник Восьмиугольник

7. Квадрат Прямоугольник

8. Квадрат Параллелограмм

9. Квадрат Трапеция

10. Квадрат Шестиугольник

11. Квадрат Восьмиугольник

12. Прямоугольник Параллелограм

13. Прямоугольник Трапеция

14. Прямоугольник Шестиугольник

15. Прямоугольник Восьмиугольник

16. Параллелограмм Трапеция

17. Параллелограмм Шестиугольник

18. Параллелограмм Восьмиугольник

19. Трапеция Шестиугольник

20. Трапеция Восьмиугольник

21. Шестиугольник Восьмиугольник

 

Контрольные вопросы

1. Различают 4 элемента определения функции: тип, имя, список параметров, тело. Какими элементами могут отличаться экземпляры одной виртуальной функции, находящиеся в разных производных классах? А в переопределенной функции внутри одного класса?

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

virtual int GetArea()=0

строкой

int GetArea(){}? Покажите эти изменения, используя режим отладки.

3. При компиляции вышеприведенной программы появляется 1 предупреждение. Чего хочет компилятор?

4. В каких случаях применяется фабрика объектов?

5. В нижеследующей программе выполните правильное обращение к функции speak производного класса, для чего замените одиночные знаки «?» корректными символами или вообще уберите их, а сдвоенные знаки «??» замените именами классов.

class Based {

public: virtual void speak() {cout<<“Hello, Based”<<endl;}

}; //Based

class Derived: public Based {

public: void speak(){cout<<“Hello, Derived”<<endl;}

}; //Derived

void print ( Based* p){p->speak();}

void main()

{ ?? ?d1;

?d1=new ??;

print (?d1);

}

Замените в функции print стрелку точкой, а * ссылкой и снова произведите замены ? и ??.

 


Лабораторная работа 4. Создание информационно-справочных систем на С++



<== предыдущая лекция | следующая лекция ==>
Базовый и производные классы | Контейнеры.


Карта сайта Карта сайта укр


Уроки php mysql Программирование

Онлайн система счисления Калькулятор онлайн обычный Инженерный калькулятор онлайн Замена русских букв на английские для вебмастеров Замена русских букв на английские

Аппаратное и программное обеспечение Графика и компьютерная сфера Интегрированная геоинформационная система Интернет Компьютер Комплектующие компьютера Лекции Методы и средства измерений неэлектрических величин Обслуживание компьютерных и периферийных устройств Операционные системы Параллельное программирование Проектирование электронных средств Периферийные устройства Полезные ресурсы для программистов Программы для программистов Статьи для программистов Cтруктура и организация данных


 


Не нашли то, что искали? Google вам в помощь!

 
 

© life-prog.ru При использовании материалов прямая ссылка на сайт обязательна.

Генерация страницы за: 2.556 сек.