简体   繁体   中英

Virtual inheritance to generalise code among two different abstract child classes

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 eg 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 eg externally connected to eg 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

Same impl as CommonBaseForJsonDynamicAppImpl1::general_functionality

If that's the case, then a core assumption in your class hierarchy is false. That is, the reason why CommonBaseForDynamicApp uses Base as a base class is because these two pieces of functionality interact. The fact that you can implement these in the same way is evidence that they don't belong in the same class hierarchy.

It seems clear to me that whatever CommonBaseForDynamicApp represents, it isn't something that necessarily needs the stuff from Base . As such, it should not be in the same class hierarchy. Maybe it's something that certain types have rather than something certain types are .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM