Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лабораторная работа 18.doc
Скачиваний:
36
Добавлен:
11.04.2015
Размер:
93.7 Кб
Скачать

Вопросы:

Что, если в производных классах Child и GrandChild опустить ключевое слово virtual перед функцией-членом answerName?

Программа будет работать отлично. Ключевое слово virtual необходимо в полиморфическом кластере только перед виртуальной функцией самого верхнего уровня. Для всех остальных переопределений этой функции ключевое слово virtual необязательно.

Что, если убрать ключевое слово virtual перед всеми функциями-членами answerName?

На выходе получим:

My last name is Иванов

My last name is Иванов

My last name is Иванов

Для реализации полиморфизма можно использовать ссылки на объекты вместо указателей.

void main(void) {

Parent p(“Иванов”);

Child c(“Иванов”,”Сергей”);

CrandChild g(“Иванов”,”Андрей”,”Владимир”);

Parent &f0=p, &f1=c; &f2=g;

f0.answerName();f1.answerName();f2.answerName();

}

Рассмотрим тонкости виртуальной функции

class P {

private:

virtual void method1(void) {}

void method2(void){}

void method3(void){method1(); method2();} // this->method1, this->method2

void method5(void){}

public:

void method6(void){method3();}

void method4(void){}

void method7(void){method5(); }

};

class C:public P {

private:

void method1(void) {}

void method5(void) {}

public:

C(){}

void method4(void) {}

void method7(void) { method5(); }

};

void main() {

P pop;

C me;

pop.method6(); // P::method1, P::method2

me.method6(); // C::method1, P::method2

pop.method4(); // P::method4

me.method4(); // C::method4

pop.method7(); // P::method5

me.method7(); // C::method5

}

Сообщение method6() посылается объекту me. Это сообщение унаследовано из класса P. Вызывается защищенный метод method3() и, затем, защищенные методы method1() и method2(). Так как method1() объявлен в базовом классе Р виртуальным, система на этапе выполнения программы связывает сообщение this->method1() с method1() класса C.

При перегрузке функции-члена виртуальный функции способны вызвать смешивание и беспорядок.

class B {

public:

virtual foo(int);

virtual foo(double);

};

class D: public B {

public:

foo(int);

};

void main() {

D d; B b, *pb=&d;

b.foo(9); // B::foo(int);

b.foo(9.5); // B::foo(double)

pb->foo(9.5); // B::foo(double);

pb->foo(9); // D::foo(int)

}

Функция-член базового класса B::foo(int) в порожденном переопределена. Функция-член базового класса B::foo(double) в порожденном классе скрыта.

Virtual могут быть только нестатические функции-члены. Функция порожденного класса автоматически становится виртуальной. Специальным ограничением является: деструкторы могут быть виртуальными, а конструкторы - нет.

Рассмотрим пример преимущества использования виртуальных функций для упрощения кода:

class shape {

protected:

double x,y;

public:

virtual double area() { return 0.; }

};

class rectangle: public shape {

double height,width;

public:

double area() { return (height*width); }

};

class circle: public shape {

double radius;

public:

double area() { return (PI*radius*radius); }

};

Вычисление площади является локальной ответственностью порожденного класса. Код пользователя, который использует полиморфное вычисление площади, может выглядеть так:

shape *p[N];

..........

for(i=0; i<N; i++) tot_area+=p[i]->area();

Здесь главное преимущество состоит в том, что код пользователя не нуждается в изменении, даже если к системе добавляются новые формы. Изменения управляются локально и распространяются автоматически, благодаря полиморфному характеру кода пользователя.