Функция Shape_area () определяется как:
uint32_t Shape_area(Shape const * const me) {
return (*me->vptr->area)(me);
}
Это означает, что функция Shape_area()
принимает указатель на структуру типа Shape.
Таким образом, чтобы добраться до фактического указателя функции для виртуальной функции, определения для различных структур следующие:
Первая структура - это фактическая структура данных, которая содержит данные вместе с указателем виртуальной функции.
typedef struct {
struct ShapeVtbl const *vptr; /* <== Shape's Virtual Pointer */
int16_t x; /* x-coordinate of Shape's position */
int16_t y; /* y-coordinate of Shape's position */
} Shape;
Существует два элемента данных, x
и y
, а также указатель на виртуальный указатель, который будет содержать указатель на фактическую функцию, которая будет использоваться.
Указатель на виртуальную функцию заключен в структуру и определен как:
struct ShapeVtbl {
uint32_t (*area)(Shape const * const me);
};
Так что, если мы используем одну из этих структур данных, это будет что-то вроде следующего фрагмента исходного кода.
uint32_t doVirt (Shape const * const me)
{
// do things with the x and y data from variable me.
// reference me->x and me->y to access those values.
return 0;
}
struct ShapeVtbl myVirt = { doVirt }; // create a struct containing pointer to our function
Shape myShape; // define our data structure
myShape.x = 32; // set the x coordinate
myShape.y = 45; // set the y coordinate
myShape.vptr = &myVirt; // set the pointer to the virtual function pointer.
Shape_area (&myShape); // call Shape_area with our struct.
Функция Shape_area()
примет указатель на структуру myShape
и затем получит доступ к виртуальной функции, указанной с помощью предоставленного указателя функции.
Если мы посмотрим на таблицу приоритетов операторов , то увидим, что *me->vptr->area
совпадает с *(me->vptr->area)
или другими словами, звездочка используется для разыменования указателя функции с использованием стандартного синтаксиса разыменования указателя.
Однако с указателями на функции этот синтаксис не является необходимым, хотя он все еще может быть выполнен. Так что (*me->vptr->area)()
- это то же самое, что (me->vptr->area) ()
- это то же самое, что и me->vptr->area()
из-за правил приоритета оператора.