Виртуальная функция эмулируется в C - PullRequest
1 голос
/ 21 мая 2019

У меня есть пример кода на C, который эмулирует виртуальную функцию Shape_area ().

Есть одна строка кода, которую я не понимаю: return (*me->vptr->area)(me);

Почему мы используем «*» перед «мной»?

Не могли бы вы объяснить мне эту часть, пожалуйста? Спасибо

/*shape.h*/

struct ShapeVtbl; /* forward declaration */
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;

/* Shape's virtual table */
struct ShapeVtbl {
    uint32_t (*area)(Shape const * const me);
};

/* Shape's operations (Shape's interface)... */
void Shape_ctor(Shape * const me, int16_t x, int16_t y);
void Shape_moveBy(Shape * const me, int16_t dx, int16_t dy);

uint32_t Shape_area(Shape const * const me) {
    return (*me->vptr->area)(me);
}

Ответы [ 2 ]

6 голосов
/ 21 мая 2019

Если это указатель на функцию, он не требуется. То же самое с или без.

Идея состоит в том, что это «указатель на функцию», поэтому вы хотите разыменовать указатель, чтобы иметь возможность использовать его как функцию. Но имена функций по сути являются просто указателями, и вам не нужно также разыменовывать их, поэтому они эквивалентны.

(*me->vptr->area)(me) эквивалентно (me->vptr->area)(me), как printf("foo") эквивалентно (*printf)("foo") (хотя вы никогда не напишите это так).

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

2 голосов
/ 22 мая 2019

Функция 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() из-за правил приоритета оператора.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...