|
5.2. Виртуальные функции. Абстрактные классы5.2.1. Виртуальные функцииВиртуальные функции – функции базового класса, которые можно заместить в каждом производном классе. Если базовый класс вызывает перегруженную виртуальную функцию, то всегда будет вызываться функция наследника. Для того, чтобы сделать функцию виртуальной, при ее описании в базовом классе необходимо указать ключевое слово virtual virtual void print() const; ////////////////////////////////////////////// void main () { // виртуальные функции важны, когда создаются указатели на класс Detail *p=new Lens; } ////////////////////////////////////////////// Реализация функции в базовом классе не изменится, а классе-наследнике и реализация и описание функции останется прежним. Использование виртуальных функций важно, когда создается экземпляр указателя на класс-наследник, если при этом экземпляр описан как базовый класс, но создается как наследник. Detail *p=new Lens;
При этом:
Делать виртуальными можно практически все функции, за исключением конструкторов и оператора =. Особый интерес представляют виртуальные деструкторы. Виртуальным деструктор делают, если для правильного осовобождения памяти необходимо, чтобы деструктор всегда вызывался для класса-наследника. 5.2.2. Абстрактные классыНекоторые базовые классы (например, класс Detail) представляют собой абстрактную концепцию, для которой не могут существовать экземпляры. Невозможно нарисовать абстрактную деталь или выполнить расчет прохождения луча через деталь. В таких случаях базовый класс делают абстрактным, то есть классом, экземпляр которого создать нельзя, но можно создать экземпляры его наследников. Абстрактным называется класс, имеющий чисто виртуальные функции. Чисто виртуальная функция – это функция, которая не определена в базовом классе, и обязательно должна быть перегружена в классах наследниках. Если какая-то абстрактная функция не будет перегружена в классе наследнике – компилятор выдаст сообщение об ошибке. В результате функции базового класса могут безопасно вызывать любые свои функции, в том числе и виртуальные, потому что они гарантированно будут перегружены в классах наследниках. Рассмотрим как будет выглядеть описание абстрактного базового класса Деталь из примера 5.1. Реализация базоваго класса, и описание и реализация классов-наследников не изменятся. ///////////////////////////////////////////////////////////////////////////// // класс Деталь - базовый класс для всех оптических деталей class Detail { protected: // координата детали по оси z double m_z; // диаметр детали double m_D; public: // конструкторы и деструктор Detail(); Detail(double z, double D); virtual ~Detail(); // установить диаметр детали void Set_D(double D); // получить диаметр детали double Get_D() const; // установить координату по оси z void Set_z(double z); // получить координату по оси z double Get_z() const; // печать параметров детали virtual void print() const; // вычисление хода луча через деталь // должно быть реализовано во всех классах-наследниках virtual void RayTrace() = 0; }; ///////////////////////////////////////////////////////////////////////////// Тестирующая функция для абстрактного класса: /////////////////////////////////////////////////////////////////////// void main() { // массив указателей на детали vector<Detail*> details(2); // первый элемент - линза details[0] = new Lens; // второй элемент - зеркало details[1] = new Mirror; // печать всех деталей cout<<"-------------------------"<<endl; for(size_t i=0; i<details.size(); ++i) { details[i]->print(); } // расчет хода луча через все детали cout<<"-------------------------"<<endl; for(size_t i=0; i<details.size(); ++i) { details[i]->RayTrace(); } // освобождение памяти для всех деталей (вызов деструкторов) cout<<"-------------------------"<<endl; for(size_t i=0; i<details.size(); ++i) { delete details[i]; } } ///////////////////////////////////////////////////////////////////////////// |