Внешняя скорость передачи данных hdd. Скорость передачи данных. Время доступа full stroke

Nokia 20.03.2019
Nokia

Виртуальная функция

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

Виртуальные методы - один из важнейших приёмов реализации полиморфизма . Они позволяют создавать общий код, который может работать как с объектами базового класса, так и с объектами любого его класса-наследника. При этом, базовый класс определяет способ работы с объектами и любые его наследники могут предоставлять конкретную реализацию этого способа. В некоторых языках программирования , например в с англ. pure virtual ) или абстрактными. Класс, содержащий хотя бы один такой метод, тоже будет абстрактным . Объект такого класса создать нельзя (в некоторых языках допускается, но вызов абстрактного метода приведёт к ошибке). Наследники абстрактного класса должны предоставить реализацию для всех его абстрактных методов, иначе они, в свою очередь, будут абстрактными классами.

Для каждого класса, имеющего хотя бы один виртуальный метод, создаётся таблица виртуальных методов . Каждый объект хранит указатель на таблицу своего класса. Для вызова виртуального метода используется такой механизм: из объекта берётся указатель на соответствующую таблицу виртуальных методов, а из неё, по фиксированному смещению, - указатель на реализацию метода, используемого для данного класса. При использовании множественного наследования или интерфейсов ситуация несколько усложняется за счёт того, что таблица виртуальных методов становится нелинейной.

Пример

Пример виртуальной функции в Delphi

Достаточно часто виртуальные методы забывают перекрыть с помощью ключевого слова override . Это приводит к закрытию метода. В этом случае замещения методов в VMT не произойдет и требуемая функциональность не будет получена.

Эта ошибка отслеживается компилятором, который выдаёт соответствующее предупреждение.

Вызов метода предка из перекрытого метода

Бывает необходимо вызвать метод предка в перекрытом методе.

Объявим два класса. Предка(Ancestor):

TAncestor = class private protected public {Виртуальная процедура.} procedure VirtualProcedure; virtual; end;

и его потомка (Descendant):

TDescendant = class (TAncestor) private protected public {Перекрытие виртуальной процедуры.} procedure VirtualProcedure; override; end;

Обращение к методу предка реализуется с помощью ключевого слова ""inherited""

procedure TDescendant.VirtualProcedure; begin inherited; end;

Стоит помнить, что в Delphi, деструктор должен быть обязательно перекрытым. ""override""; и содержать вызов деструктора предка

TDescendant = class (TAncestor) private protected public destructor Destroy; override; end; destructor TDescendant. Destroy; begin inherited; end;

В языке C++, не нужно вызывать конструктор и деструктор предка, деструктор должен быть виртуальным. Деструкторы предков вызовутся автоматически. Чтобы вызвать метод предка, нужно явно вызвать метод:

Class Ancestor { public : virtual void function1 () { printf ("Ancestor::function1" ) ; } } ; class Descendant: public Ancestor { public : virtual void function1 () { printf ("Descendant::function1" ) ; Ancestor::function1 () ; // this will print the text "Ancestor::function1" } } ;

Для вызова конструктора предка нужно указать конструктор:

Class Descendant: public Ancestor { public : Descendant() : Ancestor() ; } ;

См. также

Ссылки

  • C++ FAQ Lite: Виртуальные функции в C++ (англ.)

Wikimedia Foundation . 2010 .

Виртуальные функции - специальный вид функций-членов класса. Виртуальная функция отличается об обычной функции тем, что для обычной функции связывание вызова функции с ее определением осуществляется на этапе компиляции. Для виртуальных функций это происходит во время выполнения программы.

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

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

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

#include
using namespace std;
class X
{
protected :
int i;
public :
void seti(int c) { i = c; }
virtual void print() { cout << endl << "class X: " << i; }
};
class Y: public X // наследование
{
public :
void print() { cout << endl << "class Y: " << i; } // переопределение базовой функции
};
int main()
{
X x;
X *px = &x; // Указатель на базовый класс
Y y;
x.seti(10);
y.seti(15);
px->print(); // класс X: 10
px = &y;
px->print(); // класс Y: 15
cin.get();
return 0;
}

Результат выполнения

В каждом случае выполняется различная версия функции print() . Выбор динамически зависит от объекта, на который ссылается указатель.

Если в строке 9 (см. код выше) убрать ключевое слово virtual , то результат выполнения будет уже другим, т.к. связывание функций будет происходить на этапе компиляции:

В терминологии ООП «объект посылает сообщение print и выбирает свою собственную версию соответствующего метода». Виртуальной может быть только нестатическая функция-член класса. Для порожденного класса функция автоматически становится виртуальной, поэтому ключевое слово virtual можно опустить.

Пример : выбор виртуальной функции

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

#include
using namespace std;
class figure
{
protected :
double x, y;
public :
figure(double a = 0, double b = 0) { x = a; y = b; }
virtual double area() { return (0); } // по умолчанию
};
class rectangle: public figure
{
public :
rectangle(double a = 0, double b = 0) : figure(a, b) {};
double area() { return (x*y); }
};
class circle: public figure
{
public :
circle(double a = 0) : figure(a, 0) {};
double area() { return (3.1415*x*x); }
};
int main()
{
figure *f;
rectangle rect(3, 4);
circle cir(2);
double total = 0;
f = ▭
f = ○
total = f->area();
cout << total << endl;
total += f->area();
cout << total << endl;
cin.get();
return 0;
}

Результат выполнения


Чистая виртуальная функция

Базовый класс иерархии типа обычно содержит ряд виртуальных функций, которые обеспечивают динамическую типизацию. Часто в самом базовом классе сами виртуальные функции фиктивны и имеют пустое тело. Определенное значение им придается лишь в порожденных классах. Такие функции называются чистыми виртуальными функциями .

Чистая виртуальная функция - это метод класса, тело которого не определено.

В базовом классе такая функция записывается следующим образом.



Рекомендуем почитать

Наверх