русс | укр

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

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

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

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


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

Виртуальные методы. Полиморфизм C++

Виртуальные методы

К механизму виртуальных функций обращаются в тех случаях, когда в класс необходимо поместить функцию, которая выполняется в наследуемых классах иначе, чем в классе базовом. Виртуальные функции необходимы потому, что используются для поддержки динамического полиморфизма. Это свойство ООП поддерживается двумя способами: — на этапе компиляции, посредством перегрузки функций, и — во время выполнения программы, посредством виртуальных функций.  Виртуальные функции реализуют тезис: “один  интерфейс — множество методов“. Классы, содержащие одну или несколько виртуальных функций, называются полиморфными.

 

 Как работают виртуальные функции

Если в базовом классе функция объявлена как виртуальная, то её вызовы будут обрабатываться методом динамического связывания. Ключевое слово virtual предписывает компилятору генерировать дополнительную информацию о функциях.

Предположим, что существует класс GrafObj(x,y) — базовый класс, исходный от него класс Cub(d,w). При создании объекта класс Cub, сначала выполниться конструктор базового класса.

на рисунках представлены схемы работы виртуальной функции Draw VPTR — указатель на таблицу виртуальных функций. Эта таблица содержит указатели на все виртуальные функции класса. При инициализации объекта Cub указатель VPTR указывает на Draw(GrafObj), после работы конструктора самого класса Cub, он перенастраивается для функции Draw для класса Cub (если есть на что настраиваться). Особенностью работы с виртуальными функциями является то ,что они работают только при обращении к ним по ссылке или указателю.

 

#include<iostream.h>

class X
{        public:
virtual double A(double x)
{        return x*x;    }
double B(double x)
{        cout<<A(x)<<":2=";
return A(x)/2.;          }
};
class Y:public X
{        public:
double A(double x)
{        return x*x*x;            }
};
int main(void)
{
Y y;
X x;
cout<<"при x=3."<<endl;
cout<<x.B(3.)<<" X"<<endl;
cout<<y.B(3.)<<" Y"<<endl;
}

 

Результат выполнения  программы:

при x=3.
9:2=4.5 X                A::X=x*x;
27:2=13.5 Y           A::Y=x*x*x

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

 

#include<iostream.h>

class Mammal
{        public:
Mammal():itsAge(1){}
virtual ~Mammal() {}
virtual void Speak() { cout<< " Млекопитающее что-то сказало!\n";}
protected:
int itsAge;
};
class Dog:public Mammal
{        public:
void Speak(){cout<<"Гафф!\n";}
};
class Cat:public Mammal
{        public:
void Speak(){cout<<"Мурр!\n";}
};
void VFunc(Mammal);
void PFunc(Mammal*);
void RFunc(Mammal&);

int main(void)
{
Mammal *prt=0;
int choice;
while(1)
{
bool fQ=false;
cout<<"1--собака, 2-- кошка, иначе-- млекопитающее, 0-- выход.";
cin>> choice;
          switch(choice)
          {
          case 0: fQ=true;break;
          case 1: prt=new Dog; break;
          case 2: prt=new Cat; break;
          default: prt=new Mammal;
          }
          if(fQ) break;
cout<<"указатель на класс:  " ; Pfunc(prt);
cout<<"ссылка на класс: "; Rfunc(*prt);
cout<<"переменная класса:  -- "; VFunc(*prt);
}
return 0;
}

void VFunc(Mammal M)
{        MV.Speak();            }
void PFunc(Mammal *pM)
{        pM->Speak();          }
void RFunc(Mammal &rM)
{        rM.Speak();  }

 

Результат работы программы:

1--собака, 2-- кошка, иначе-- млекопитающее, 0-- выход. 1
указатель на класс:     -- Гафф!
ссылка на класс:        -- Гафф!
переменная  класса:  -- Млекопитающее что-то сказало!
1--собака, 2-- кошка, иначе-- млекопитающее, 0-- выход. 2
указатель на класс:     -- Мурр!
ссылка на класс:        -- Мурр!
переменная  класса:  -- Млекопитающее что-то сказало!
1--собака, 2-- кошка, иначе-- млекопитающее, 0-- выход. 3
указатель на класс:     -- Млекопитающее что-то сказало!
ссылка на класс:        -- Млекопитающее что-то сказало!
переменная  класса:  -- Млекопитающее что-то сказало!
1--собака, 2-- кошка, иначе-- млекопитающее, 0-- выход. 0

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

Конструктор не может быть виртуальным и не может быть виртуального конструктра-копировщика. Если требуется передать указатель на объект произвольного класса и правильно скопировать его можно использовать виртуальный метод Clone()— создающий и возвращающий копию объекта текущего класса.

Virtual Mammal* Mammal::Clone(){return new Mammal(*this);}
Virtual Mammal* Dog::Clone(){return new Dog(*this);}
Virtual Mammal* Cat::Clone(){return new Cat(*this);}

Существует цена виртуальных методов так как необходимо поддерживать v-таблицу ,( снижение быстродействия и затраты на память), а так же необходимость писать виртуальный деструктор. Поэтому необходимо обосновывать необходимость использования виртуальных методов ( если да, то какие именно).

Рекомендуется:

  • Используйте виртуальные методы только в том случае, если программа содержит базовый и производный классы.
  • Используйте виртуальный деструктор, если в программе был созданы виртуальные методы.
  • Не пытайтесь создать виртуальный конструктор.

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

 

Абстрактные классы

Очень часто виртуальная функция, объявленная в базовом классе, никогда не используется в нём, то  есть она представляется в виде пустой функции ( { } ).

Версия виртуальной функции, которая должна быть определена, но никогда не будет использоваться, должна быть объявлена как чисто виртуальная :
Virtual тип имя_функции (список параметров) =0;
При выполнении в программе число виртуальной функции генерируется сообщение об ошибке и программа аварийно завершается (при работе пустой функции этого не происходит).

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

Рекомендации:

  • Используйте абстрактные типы данных для создания для создания общего интерфейса для всех производных классов.
  • Обязательно замещайте в произвольных классах чистые виртуальные функции.
  • Объявляйте все функции, которые требуют замещения в произвольном классе как виртуальные.
  • Не пытайтесь создать объект абстрактного класса.

Просмотров: 20220

Вы можете --> Заказать программу или Задать вопрос на форуме

Вернуться воглавление


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


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

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

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


 


Полезен материал? Поделись:

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

 
 

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