配置类也使用继承时的继承

inheritance when config classes also use inheritance

我很难为这个问题设计一个优雅的解决方案。我已将其简化为本质,但这是我正在努力应对的现实情况。

问题是 Base 和 Sub 都有自己的 Config classes 副本。当我在 SubConfig 中更改某些内容时,它不会影响 Base 持有的副本,因此不会影响 Base 的行为。

我已经解决了机制问题,但我的解决方案很丑陋。如果您愿意,请向下滚动到示例代码下方以了解详细信息。

#include <cstdio>

struct BaseConfig
{
        BaseConfig(int a_) : a(a_) {}
        int a;
};

struct Base
{
        BaseConfig config;
        Base(BaseConfig& c) : config(c) {}
        void FuncBase() { printf("a=%d\n",config.a); }
};

struct SubConfig : public BaseConfig
{
        SubConfig(int a_, int b_) : BaseConfig(a_), b(b_) {}
        int b;
};

struct Sub : public Base
{
        SubConfig config;
        Sub(SubConfig& c) : Base(c), config(c) {}
        void FuncSub() { printf("a=%d\nb=%d\n",config.a, config.b); }
};

int main(int argc, char** argv)
{
        SubConfig sc(1,2);
        Sub s(sc);
        {
                printf("Initial state\n");
                s.FuncBase();
                s.FuncSub();
        }
        {
                printf("Changing a to 3\n");
                s.config.a = 3;
                s.FuncBase();
                s.FuncSub();
        }
        return 0;
}

现在是我丑陋的解决方案。它在 Base 中同时使用一个对象和一个 BaseConfig 指针。当直接初始化Base时,它使用它的对象变量,并将它的指针设置为对象的地址,所以它使用它自己的BaseConfig副本。当它被 Sub 初始化时,它使用一个指向 Sub 的 SubConfig 的指针。 Base 使用指针版本,因此在这种情况下它将使用 SubConfig 的设置副本。

// config classes are unchanged

struct Base
{
        BaseConfig* config;
        Base(BaseConfig* c) : config(c), _configObj(*c) {}
        Base(const BaseConfig& c) : config(&_configObj), _configObj(c) {}
        void FuncBase() { printf("a=%d\n",config->a); }
protected:
        BaseConfig _configObj;
};

struct Sub : public Base
{
        SubConfig config;
        Sub(const SubConfig& c) : Base(&config), config(c) {}
        void FuncSub() { printf("a=%d\nb=%d\n",config.a, config.b); }
};

请告诉我有一个明显而优雅的方法来完成这项工作!

如果 Sub 和 Base 共享配置对象,您就不会遇到问题。 实现此目的的一个简单解决方案是使用指针(智能指针)来配置 Base 和 Sub 中的 classes。然后他们可以共享公共配置对象,另外构造函数将是统一的(Base 不会有两个构造函数)。我稍微改变了你的解决方案:

// config classes are unchanged

struct Base
{
    BaseConfig* config;
    Base(BaseConfig* c) : config(c) {}
    void FuncBase() { printf("a=%d\n",config->a); }
    ~BaseConfig() { delete config; }
};

struct Sub : public Base
{
    SubConfig* config;
    Sub(SubConfig* c) : Base(config), config(c) {}
    void FuncSub() { printf("a=%d\nb=%d\n",config->a, config->b); }
};

但必须明确说明,配置对象的所有者是 Base class,它负责配置释放。 如果你会使用例如c++11 std::shared_ptr class 存储配置然后释放配置对象的问题将消失。

我想到了一种可能的方法,我更喜欢这种方法而不是问题中的丑陋方法。

让函数 类(基础和子)继承它们的配置 类。并使用虚继承保证每个Config变量只有一份。

像这样:

#include <cstdio>

struct BaseConfig
{
        BaseConfig(int a_) : a(a_) {}
        int a;
};

struct Base : virtual BaseConfig
{
        Base(const BaseConfig& c) : BaseConfig(c) {}
        void FuncBase() { printf("a=%d\n",this->a); }
};

struct SubConfig : public virtual BaseConfig
{
        SubConfig(int a_, int b_) : BaseConfig(a_), b(b_) {}
        int b;
};

struct Sub : public Base, public SubConfig
{
        Sub(const SubConfig& c) : BaseConfig(c), Base(c), SubConfig(c) {}
        void FuncSub() { printf("a=%d\nb=%d\n", this->a, this->b); }
};

int main(int argc, char** argv)
{
        SubConfig sc(1,2);
        Sub s(sc);
        s.FuncBase();
        s.FuncSub();
        {
                printf("Changing a to 3\n");
                s.a = 3;
                s.FuncBase();
                s.FuncSub();
        }
        {
                printf("Changing b to 4\n");
                s.b = 4;
                s.FuncBase();
                s.FuncSub();
        }
        return 0;
}

我仍在寻找其他能做得更好的答案。