I have an interface which is behavioral in the sense that provides some functionality that can be applied to a certain data shape. For example, a hierarchical data structure.
Firstly, let us define the base class
class Base {
virtual void general_functionality() = 0;
virtual void general_functionality1() = 0;
};
Then, I have another abstract class which inherits from Base but it also add a few more interfaces that are specific e.g a dynamic hierarchical data structure (data that can be altered by having it synced to a Database for example)
class CommonBaseForDynamicApp : public Base {
virtual void apply_dynamic_logic() = 0;
};
Now let us look at the first implementation where we have a Json based data structure. (implementation code left)
class CommonBaseForJsonDynamicAppImpl1 : public CommonBaseForDynamicApp {
void apply_dynamic_logic() override {};
void general_functionality() override {};
void general_functionality1() override {};
};
And we can have another like Yaml based
class CommonBaseForYamlDynamicAppImpl1 : public CommonBaseForDynamicApp {
void apply_dynamic_logic() override {};
void general_functionality() override {};
void general_functionality1() override {};
};
Now we also want to support Json based data structure where the underlaying data won’t be e.g. externally connected to e.g. a DB. Therefore, I will now directly inherit from Base
again.
class CommonBaseForJsonStaticApp : public Base {
void general_functionality() override {};// Same impl as CommonBaseForJsonDynamicAppImpl1::general_functionality;
void general_functionality1() override {};// Same impl as CommonBaseForJsonDynamicAppImpl1::general_functionality1;
};
As you can see from above, the design is abit problematic due to the fact that we got duplication of code. Many of the static and dynamic applications overlap.
The first solution I thought of is to make use of virtual inheritance. Here, we implement a class that is directly inherited from Base
class CommonForJson : public Base {
void general_functionality() override {};
void general_functionality1() override {};
};
Then, our static case could directly inherit from that (in this case it does not have to since no additional code is needed).
class CommonBaseForJsonStaticApp : public CommonForJson {
};
For the dynamic case we must inherit from two places namely and make use of virtual inheritance. :
class CommonBaseForJsonDynamicAppImpl : public CommonBaseForDynamicApp, virtual CommonForJson {
void apply_dynamic_logic() override {};
};
While the above will work, I suspect this type of inheritance and tight coupling might create problems in the long run. So I want to ask whether the above issue has alternative design patterns which are more ideal – I assume this problem might have been faced by others as well.
We are using c++-20