Студопедия

КАТЕГОРИИ:


Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748)

Статичне і динамічне зв’язування: поліморфізм, віртуальні функції, заміщення (overriding) функцій, віртуальні деструктори

 

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

у батьківському класі, але й замістити його іншим (заміщення — overridding).

Причому рішення про те, яку саме функцію буде викликано приймається на етапі

виконання програми залежно від конкретного типу створеного об'єкту. Це явище,

при якому об'єкти одного типу (підкласи) заміщують об'єкти іншого типу (суперкласу)

дістало назву поліморфізму.

 

Наступний приклад показує просте застосування поліморфізму

 

 

Заміщувані функції, як і абстрактні, позначаються як віртуальні.

Це свого роду невеликий пережиток мови С++, оскільки в пізніших мовах необхідність

виділення віртуальних функцій відпала — замістити можна будь-яку функцію.

 

class Shape

{

public:

virtual void whatAmI();

};

void Shape::whatAmI()

{

cout <<"I don't know what kind of shape I am!\n";

}

class Rectangle: public Shape

{

public:

void whatAmI();

};

void Rectangle::whatAmI()

{

cout << "I'm a rectangle!\n";

}

class Triangle: public Shape

{

public:

void whatAmI();

};

void Triangle::whatAmI()

{

cout << "I'm a triangle!\n";

}

 

Зверніть увагу, в усіх трьох випадках виклику методу whatAmI використовується

указник одного й того ж типу, але викликаються різні методи, залежно від типу

значення, на яке указник встановлено. Ясно, що використання імен замість указників,

зробило б поліморфізм неможливим.

 

int main()

{

Shape *s1, *s2, *s3;

 

s1 = new Rectangle;

s2 = new Triangle;

s3 = new Shape;

 

s1->whatAmI();

s2->whatAmI(); (*)

s3->whatAmI();

 

return 0;

}

 

Особливу роль відіграють віртуальні деструктори. Вони призначені

для виклику правильних деструкторів у випадку поліморфізму. Ось вже відомий

нам приклад. Якби деструктор не був віртуальним, то після створенні прямокутника

викликався б лише деструктор фігури, а тому пам'ять, виділена під прямокутник

залишилася б не звільненою.

 

const int sizeOfShape=100;

const int sizeOfRec=60;

class Shape

{

public:

double *description;

Shape()

{

cout<<"Shape constructor was called"<<endl;

description = new double[sizeOfShape];

}

virtual void whatAmI();

virtual ~Shape()

{

delete [] description;

cout<<"Shape destructor was called"<<endl;

}

};

void Shape::whatAmI()

{

cout << "I don't know what kind of shape I am!\n";

}

class Rectangle: public Shape

{

public:

double *description;

Rectangle()

{

cout<<"Rectangle constructor was called"<<endl;

description = new double[sizeOfRec];

}

virtual void whatAmI();

~Rectangle()

{

delete [] description;

cout<<"Rectangle destructor was called"<<endl;

}

};

void Rectangle::whatAmI()

{

cout << "I'm a rectangle!\n";

}

 

int main()

{

Shape *s1, *s2;

 

s1 = new Shape;

s1->whatAmI();

delete s1;

 

cout<<endl;

 

s2 = new Rectangle;

s2->whatAmI();

delete s2;

 

return 0;

}

 

Останній приклад показує спосіб, яким можна звичайний масив замінити масивом

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

віртуальною

 

class IntArray

{

public:

.......

 

IntArray& operator= (const IntArray&);

virtual int& opetator[] (int index);

 

int size() const;

.......

}

class IntArrayRC: public IntArray

{

public:

IntArrayRC (int sz=defaultArraySize):IntArray(sz){};

IntArrayRC (int* array, int sz):

IntArray(array, sz){};

IntArrayRC (const IntArray&):IntArray(r){};

 

int& operator[] (int index);

private:

void checkRange(int index);

}

int& IntArrayRC::operator[] (int index)

{

checkRange(index);

return ia[index];

}

#include

void IntArrayRC:: checkRange(int index)

{

assert (index>=0 && index <_size);

}

 

Ще ближче до повного рішення:

 

template

class ArrayRC: public Array

{

public:

ArrayRC (int sz=defaultArraySize):

Array(sz){};

ArrayRC (int* array, int sz):

Array(array, sz){};

ArrayRC (const IntArray&):Array(r){};

elemType& operator[] (int index);

private:

void checkRange(int index);

}

 

Якщо кожен з базових класів випадково чи зумисне міститиме елементи з одним і

тим же іменем, то похідний клас успадкує обидва з них. Для використання таких

елементів може знадобитись уточнення, наприклад, Predator::name.

 

 

class Predator

{

private:

string favoritePrey;

protected:

string name;

public:

Predator(string aName, string aPrey);

~Predator();

setName(const string& aName);

};

class Pet

{

private:

string favoriteToy;

protected:

string name;

public:

Pet(string aName, string aToy);

~Pet();

setName(const string& aName);

};

class Cat: public Predator, public Pet

{

private:

short catID;

static short lastCatID;

public:

Cat(string aName, string aPrey, string aToy);

~Cat();

static void ShowLastID();

};

 

Не дуже добре:

 

Cat myCat(“Murka”, “Mouse” “Mouse”);

//Як Вас тепер називати?

Pet::MyCat.setName(”NotMurka”);

Predator::MyCat.setName(”StillMurka”);

 

Було б зручно мати об'єкт на зразок “іменованого звіра”, а вже від нього виводити

хижака і пестуна. Але це вже проблема успадкування із спільного базового класу.

 

 

<== предыдущая лекция | следующая лекция ==>
Статичне і динамічне зв’язування | Успадкування із спільного базового класу. Кратне (multiple) успадкування. Віртуальне успадкування, порядок виклику конструкторів
Поделиться с друзьями:


Дата добавления: 2014-01-06; Просмотров: 2894; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




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