Сдам Сам

ПОЛЕЗНОЕ


КАТЕГОРИИ







Механизм работы позднего связывания





Компилятор для каждого класса (не объекта), содержащего хотя бы один виртуальный метод, создает таблицу виртуальных функций VFTABLE. В эту таблицу помещаются адреса виртуальных функций класса в порядке их описания. Адрес любого виртуального метода имеет в VFTABLE одно и то же смещение для каждого класса в пределах иерархии. В каждом классе также помещается указатель VFPTR на таблицу виртуальный функций.

При явном связывании мы получаем абсолютные адреса функций. Теперь, вызывая функцию name(), мы говорим, что надо вызвать функцию по адресу VFPTR+1.

Наследование и таблица виртуальных функций

В случае со строкой p[1]->sit(), компилятор выдает ошибку.

Компилятор запрещает вызовы тех виртуальных функций, которые присутствуют только в производном классе классе, а так как у базового класса Animal нет функции sit(), поэтому компилятор выдает ошибку при попытке ее использования.

Но чтобы избежать ошибки, необходимо обращаться к функции sit() следующим образом:

((Dog*) p[1])->sit();

Будем считать, что классы Animal и Dog объявлены как в предыдущем примере.

//f1.cpp

#include "f1.h"

void main()

{ Dog druzhok("Druzhok");

Animal* p1=&druzhok;

Animal& p2=druzhok;

Animal p3("Druzhok");

cout<<p1->speak()<<endl; //”Druzhok Say Gav!” (Позднее связывание)

cout<<p2.speak()<<endl; //”Druzhok Say Gav!” (Позднее связывание)

cout<<p3.speak()<<endl; //” “ (Явное связывание)

}

Абстрактные базовые классы

Класс становится абстрактным, когда в него добавляется чистая виртуальная функция:

virtual void f() = 0;

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

//f1.cpp

#include <iostream.h>

#include <string.h>

class Animal

{public:

virtual char* speak() =0;

virtual char *eat() =0;

};

char* Animal::speak()

{return "Animal::speak()";}

char* Animal::eat()

{return "Animal::eat()";}

class Dog: public Animal

{public:

char *speak() {return Animal::speak();}

char *eat() {return Animal::eat();}

};

//f1.cpp

#include "f1.h"

void main()

{ Dog Sharik;

cout<<Sharik.speak()<<endl;

cout<<Sharik.eat()<<endl;

 

}

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

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

В отличие от конструкторов деструкторы могут быть виртуальными.

//f1.h

include <iostream.h>

class Base1

{public:

~Base1(){cout<<"~Base1()"<<endl;}

};

class Derived1: public Base1

{public:

~Derived1(){cout<<"~Direved1()"<<endl;}

};

class Base2

{public:

virtual ~Base2(){cout<<"~Base2()"<<endl;}

};

class Derived2: public Base2

{public:

~Derived2(){cout<<"~Direved2()";}

};

//f1.cpp

#include "f1.h"

void main()

{

Base1* bp1=new Derived1;

delete bp1; //~Base1()

Base2* bp2=new Derived2;

delete bp2; //~Derived2()~Base2()

}

Деструкторы вызываются в порядке обратном вызову конструкторов.

Чистые виртуальные деструкторы

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

//f1.h

#include <iostream.h>

class AbstractBase

{public:

virtual ~AbstractBase()=0;

};

AbstractBase::~AbstractBase()

{cout<<"Destructor Abstract Class"<<endl;}

class Derived: public AbstractBase

{

};

//f1.cpp

#include "f1.h"

void main()

{ Derived d;

}

Виртуальные функции в деструкторах

Механизм позднего связывания не действителен для виртуальных и невиртуальных деструкторов. Вызывается локальная версия виртуальной функции.

//f1.h

#include <iostream.h>

class Base

{public:

virtual ~Base() {cout<<"~Base()"<<endl; f();}

virtual void f() {cout<<"Base::f"<<endl;}

};

class Derived: public Base

{public:

~Derived() {cout<<"~Derived()"<<endl;}

virtual void f() {cout<<"Derived::f"<<endl;}

};

//f1.cpp

#include "f1.h"

void main()

{ Base *bp = new Derived;

delete bp; //"~Derived()","~Base()","Base::f"

}







Конфликты в семейной жизни. Как это изменить? Редкий брак и взаимоотношения существуют без конфликтов и напряженности. Через это проходят все...

ЧТО ТАКОЕ УВЕРЕННОЕ ПОВЕДЕНИЕ В МЕЖЛИЧНОСТНЫХ ОТНОШЕНИЯХ? Исторически существует три основных модели различий, существующих между...

ЧТО ПРОИСХОДИТ, КОГДА МЫ ССОРИМСЯ Не понимая различий, существующих между мужчинами и женщинами, очень легко довести дело до ссоры...

Что делает отдел по эксплуатации и сопровождению ИС? Отвечает за сохранность данных (расписания копирования, копирование и пр.)...





Не нашли то, что искали? Воспользуйтесь поиском гугл на сайте:


©2015- 2024 zdamsam.ru Размещенные материалы защищены законодательством РФ.