【问题标题】:Virtual function emulated in CC中模拟的虚函数
【发布时间】:2019-05-21 20:43:39
【问题描述】:

我有 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);
}

【问题讨论】:

  • 并非您在互联网上看到的每个代码都是好的
  • @P__J__ 这是通过函数指针调用函数的传统方式。后来,显式取消引用成为可选的,但许多人更喜欢保留它,因为它更清晰且与声明符更一致。这样做当然没有错。

标签: c function virtual


【解决方案1】:

如果是函数指针,则不需要。有没有都一样。

这个想法是它是一个“指向函数的指针”,因此您希望取消引用指针以便能够将其用作函数。但是函数名实际上也只是指针,你也不需要取消引用它们,所以它们是等价的。

(*me-&gt;vptr-&gt;area)(me) 等价于(me-&gt;vptr-&gt;area)(me),printf("foo") 等价于(*printf)("foo")(尽管你永远不会这样写)。

您可以保留或删除它,这并不重要。就个人而言,如果它专门指向一个函数而不是一个命名函数本身,我会保留它以保持“取消引用以使用它”的想法。

【讨论】:

  • 事实是,指针周围的括号似乎也不需要。
  • 正确,但前提是我们忽略了取消引用 *。
【解决方案2】:

函数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);
};

因此,如果我们使用其中一种数据结构,它将类似于以下源代码 sn-p。

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 结构的指针,然后访问通过提供的函数指针指定的虚函数。

如果我们查看operator precedence table,我们可以看到*me-&gt;vptr-&gt;area 与*(me-&gt;vptr-&gt;area) 相同,或者换句话说,星号用于使用标准指针解引用语法来解引用函数指针。

但是,对于函数指针,这种语法不是必需的,尽管它仍然可以完成。所以(*me-&gt;vptr-&gt;area)() 与(me-&gt;vptr-&gt;area) () 相同,由于运算符优先规则,me-&gt;vptr-&gt;area() 相同。

【讨论】:

    猜你喜欢
    • 2018-02-01
    • 2017-06-10
    • 2012-02-12
    • 2012-04-18
    • 2020-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-12
    相关资源
    最近更新 更多