为什么要在类中创建函数指针结构?

Why create a struct of function pointers inside a class?

提问人:user1801359 提问时间:9/1/2022 更新时间:9/2/2022 访问量:109

问:

我正在 Vulkan 后端挖掘 Skia 图形 API,在这里找到,但我不懂一段代码。

下面是最小的代码示例:

struct VulkanInterface : public SkRefCnt {

public:
    VulkanInterface(VulkanGetProc getProc,
                    VkInstance instance,
                    VkDevice device,
                    uint32_t instanceVersion,
                    uint32_t physicalDeviceVersion,
                    const VulkanExtensions*);

    /**
     * The function pointers are in a struct so that we can have a compiler generated assignment
     * operator.
     */
    struct Functions {
        VkPtr<PFN_vkCreateInstance> fCreateInstance;
        VkPtr<PFN_vkDestroyInstance> fDestroyInstance;

        // a ton more functions here
    } fFunctions;
};

为什么要在类中创建函数指针结构?

为什么要在任何地方添加这个额外的抽象层?fFunctions->

我知道有一条带有解释的评论,我知道这些话是什么意思,但我不理解整个评论。我只需要再分解一下。谢谢。

C++ 函数指针 赋值运算符 skia

评论

1赞 273K 9/1/2022
他们想要使用或某个地方。fFunctions = functions;fFunctions = {create, destroy};
1赞 François Andrieux 9/1/2022
如果要实现自己的运行时多态性版本,则可以执行此操作。它允许您将实例的整个行为表示为单个值。
1赞 Slava 9/1/2022
这是继承和虚拟功能的手工变体。

答:

2赞 Jarod42 9/2/2022 #1

具有常规多态性遗传

struct Base
{
    virtual ~Base() = default;
    virtual void foo();
    // ...
};

struct D1 : Base
{
    void foo() override;
    // ...
};

struct D2 : Base
{
    void foo() override;
    // ...
};

如果不进行切片,则无法分配给基类:

D1 d1;
Base b = d1;
b.foo(); // call Base::Foo

或者用语义值处理对象:

D1 d1;
D2 d2;
d2 = d1; // Illegal

您必须改用(智能)指针。

此外,您不能(在运行时)混合来自不同虚拟函数

Base base;
base.foo = &D2::foo; // imaginary syntax, Illegal
base.bar = &D1::bar; // imaginary syntax, Illegal

在类中拥有这些函数指针允许上述操作(以更大的对象为代价)。

struct VulkanInterface
{
    void (*foo) ();
    void (*bar) (VulkanInterface& self);
    // ...
};

VulkanInterface makeVulkanInterface1() { return {my_foo, my_bar}; }
VulkanInterface makeVulkanInterface2() { return {my_foo2, my_bar2}; }
VulkanInterface v1 = makeVulkanInterface1();
VulkanInterface v2 = makeVulkanInterface2();
VulkanInterface v = v1;
v = v2;
v.foo = v1.foo;
v.bar(v);