I was digging around in the Vulkan backend for the Skia graphics API, found here, and I don't understand a piece of code.
Here's the smallest code example:
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;
};
Why would you create a struct of function pointers in a class?
Why this extra layer of abstraction where you have to add fFunctions->
everywhere?
I know there's a comment with an explanation and I know what those words mean, but I don't understand the comment as a whole. I just need it broken down a little more. Thanks.
CodePudding user response:
With regular polymorphic inheritance
struct Base
{
virtual ~Base() = default;
virtual void foo();
// ...
};
struct D1 : Base
{
void foo() override;
// ...
};
struct D2 : Base
{
void foo() override;
// ...
};
You cannot assign to base class without slicing:
D1 d1;
Base b = d1;
b.foo(); // call Base::Foo
or treat object with value semantic:
D1 d1;
D2 d2;
d2 = d1; // Illegal
you have to use (smart) pointer instead.
In addition, you cannot mix (at runtime) from different virtual functions
Base base;
base.foo = &D2::foo; // imaginary syntax, Illegal
base.bar = &D1::bar; // imaginary syntax, Illegal
Having those function pointers inside the class allow the above (at the price of bigger object).
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);