Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
О.О.П / ооп / 18. Об'єктно-орієнтоване програмування, л.5.5 - 5.8.ppt
Скачиваний:
26
Добавлен:
30.05.2020
Размер:
3.38 Mб
Скачать

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

Метод класу може бути оголошений віртуальним, якщо допускається його альтернативна реалізація в породженому класі

При виклику віртуальної функції через покажчик або заслання на об'єкт базового класу буде викликана реалізація даної функції, специфічна для фактичного типа об'єкту

Віртуальні функції позначаються в оголошенні класу за допомогою ключового слова virtual

Віртуальні функції дозволяють використовувати поліморфізм

Поліморфізм дозволяє здійснювати роботу з різними реалізаціями через один і той же інтерфейс

class CShape

{

public:

virtual std::string GetType()const{return "Shape";} virtual double GetArea()const{return 0;}

};

class CRectangle : public CShape

{

public:

CRectangle(double width, double height) :m_width(width), m_height(height){}

virtual std::string GetType()const{return "Rectangle";} virtual double GetArea()const{ return m_width * m_height; }

private:

double m_width; double m_height;

};

class CCircle : public CShape

{

public:

CCircle(double radius):m_radius(radius){}

virtual std::string GetType()const{return "Circle";}

virtual double GetArea()const{return 3.14159265 * m_radius * m_radius;} private:

double m_radius;

};

void PrintShapeArea(CShape const& shape)

{

std::cout << shape.GetType() << " area: " << shape.GetArea() << "\n";

}

int main(int argc, char * argv[])

{

CCircle circle(10);

CRectangle rectangle(20, 10);

PrintShapeArea(circle);

PrintShapeArea(rectangle);

return 0;

}

Output:

Circle area: 314.159

Rectangle area: 200

Особливості реалізації віртуальних функцій в

C++

У C++ функції, оголошені в базовому класі віртуальними, залишаються віртуальними в класах-нащадках

Використовувати слово virtual в класах спадкоємцях не обов'язково (хоча і бажано)

У C++ віртуальні функції не є віртуальними, якщо вони викликані в конструкторі або деструкції даного класу

Така поведінка специфічна для механізму ініціалізації і руйнування об'єктів в C++; у інших мовах програмування може бути по- іншому

Віртуальний

деструктор

Деструкція класу, що має спадкоємців, завжди повинна явно оголошуватися віртуальним

Це забезпечує коректний виклик деструкції потрібного класу при виклику оператора delete з покажчиком на базовий клас

Деструкція, не оголошена явно віртуальним, а також деструкція, що автоматично згенерувала, є не віртуальною

Класи без віртуальних деструкцій не призначені для розширення

Класи стандартних колекцій STL (рядки, вектори) не мають віртуальних деструкцій, тому успадковуватися від них не можна

class CBase

{

public:

CBase():m_pBaseData(new char [100])

{

std::cout << "Base class data were created\n";

}

~CBase()

{

delete [] m_pBaseData;

std::cout << "Base class data were deleted\n";

}

private:

char * m_pBaseData;

};

class CDerived : public CBase

{

public:

CDerived():m_pDerivedData(new char [1000])

{

std::cout << "Derived class data were created\n";

}

~CDerived()

{

delete [] m_pDerivedData;

std::cout << "Derived class data were deleted\n";

}

private:

char * m_pDerivedData;

};

int main(int argc, char * argv[])

{

{

CDerived derived;

}

std::cout << "===\n";

CDerived * pDerived = new CDerived();

// этот объект удалится нормально

delete pDerived; pDerived = NULL;

std::cout << "===\n";

CBase * pBase = new CDerived();

/* а вот тут будет вызван лишь деструктор базового класса */

delete pBase; pBase = NULL;

return 0;

}

Output:

Base class data were created

Derived class data were created Derived class data were deleted

Base class data were deleted

===

Base class data were created Derived class data were created Derived class data were deleted

Base class data were deleted

===

Base class data were created Derived class data were created Base class data were deleted

class CBase

{

public:

CBase():m_pBaseData(new char [100])

{

std::cout << "Base class data were created\n";

}

virtual ~CBase()

{

delete [] m_pBaseData;

std::cout << "Base class data were deleted\n";

}

private:

char * m_pBaseData;

};

class CDerived : public CBase

{

public:

CDerived():m_pDerivedData(new char [1000])

{

std::cout << "Derived class data were created\n";

}

~CDerived()

{

delete [] m_pDerivedData;

std::cout << "Derived class data were deleted\n";

}

private:

char * m_pDerivedData;

};

int main(int argc, char * argv[])

{

{

CDerived derived;

}

std::cout << "===\n";

CDerived * pDerived = new

CDerived();

// этот объект удалится нормально delete pDerived; pDerived = NULL;

std::cout << "===\n";

CBase * pBase = new CDerived();

/* а вот тут будет вызван лишь деструктор базового класса */

delete pBase; pBase = NULL;

return 0;

}

Output:

Base class data were created

Derived class data were created Derived class data were deleted Base class data were deleted

===

Base class data were created Derived class data were created Derived class data were deleted Base class data were deleted

===

Base class data were created Derived class data were created Derived class data were deleted Base class data were deleted

Підводимо підсумки

Завжди використовуємо віртуальну деструкцію:

У базових класах

У класах, від яких можливе спадкоємство в майбутньому

Наприклад, в класах з віртуальними методами

Не використовуємо віртуальні деструкції

У класах, від яких не планується створювати похідні класи в майбутньому

Також можливо в базовому класі оголосити захищену невіртуальну деструкцію

Об'єкти даного видалити безпосередньо неможливо - лише через покажчик на клас-спадкоємець

Дана деструкція буде доступна класам-спадкоємцям

Абстрактні класи

Можливі ситуації, коли базовий клас є

абстрактним поняттям, і виступає лише як базовий клас (інтерфейс) для похідних класів

Неможливо дати осмислене визначення його віртуальних функцій

Яка площа об'єкту «CShape», як його намалювати?

Такі віртуальні функції слід оголошувати чисто віртуальними (pure virtual), додавши ініціалізатор =0, опустивши тіло функції

Клас є абстрактним, якщо в нім міститься хоч би одна чисто віртуальна функція, або він не реалізує хоч би одну чисто віртуальну функцію свого батька

Екземпляр абстрактного класу створити

неможливо