C ++使用mixins和多重继承来覆盖解析

时间:2018-11-28 23:57:51

标签: c++ templates override multiple-inheritance mixins

我为无法解释的以下行为感到困惑。我试图写一个有意义的标题,但不确定是否钉上了它。

首先有一些背景知识。 我编写了数值模拟软件,并尝试对代码进行一些现代化。我有三个数值解算器:primaldualadaptiveprimal求解器在工作时不知道其他任何事情。 dual求解器与primal有很多共同点,但从未单独使用,adaptive求解器是一个包含并运行primal和{{ 1}},按此顺序。 现在,问题是,当dual求解器运行其adaptive求解器时,与单独使用时相比,primal需要执行一些其他操作。让这样的操作之一为primal。另外,saveprimal有很多共同点,所以我认为它们应该在dual类中共享代码。

这是我最初的设计

common

它会打印

#include <iostream>

using namespace std;

template <typename s>
struct common
{
    void run()
    {
        static_cast<s*>(this)->save();
    }
};

struct primal : public common<primal>
{
    virtual void save()
    {
        cout << "  Primal\n";
    }
};

struct dual : public common<dual>
{
    void save()
    {
        cout << "  Dual\n";
    }
};

struct adaptive : public primal,
                  public dual
{
    void run()
    {
        primal::run();
        dual::run();
    }

    virtual void save()
    {
        primal::save();
        cout << "    Adaptive\n";
    }
};

int main(int argc, const char *argv[])
{
    adaptive a;
    a.run();
    return 0;
}

在我看来,这意味着

  1. Primal Adaptive Dual 呼叫a.run
  2. primal::run = common<primal>::run调用common<primal>::run,但是此方法为primal::save,因此它解析为调用virtual
  3. adaptive::save显式调用adaptive::save,因为我希望它执行primal::save的常规任务以及其他操作
  4. primal做其他工作并返回
  5. adaptive::save调用a.run,后者调用dual::run = common<dual>::run,但是此方法不是 dual::save,因此选择时忽略了virtual

到目前为止一切都很好,这正是我想要的。 因此,第一个问题:以上所有方法正确吗?

现在,问题来了。 经过一些重构后,adaptive::saveprimal::save现在具有相同的功能,因此我想将其放入dual::save中,并继续仅扩展common中的行为。

第一步,我将代码更改为

adaptive

现在的输出是

template <typename s>
struct common
{
    void run()
    {
        save();
    }

    virtual void save()
    {
        cout << "This should never be called\n";
    }
};

// Everything else stays the same

我期望与以前相同的输出。 这是我不了解的第一件事:在我看来, Primal Adaptive Primal Adaptive 发出的对dual::save的调用现在一直被解决到dual::run(),而我一直希望在adaptive::save处停止,因为此方法不是dual::save。 这是我的第二个问题:为什么会这样?和以前有什么不同?

最后,我在最终版本中牢记了代码,再加上一些调试内容,看起来像这样:

virtual

它会打印

#include <iostream>

using namespace std;

template <typename s>
struct common
{
    void run()
    {
        save();
    }

    virtual void save()
    {
        cout << s::name << "::common\n";
    }
};

struct primal : public common<primal>
{
    static const string name;
};
const string primal::name = "primal";

struct dual : public common<dual>
{
    static const string name;
};
const string dual::name = "dual";

struct adaptive : public primal,
                  public dual
{
    virtual void save()
    {
        primal::save();
        cout << "    Adaptive\n";
    }

    void run()
    {
        primal::run();
        dual::run();
    }
};

int main(int argc, const char *argv[])
{
    adaptive a;
    a.run();

    return 0;
}

与以前的版本一样,当时我期望的是

primal::common
    Adaptive
primal::common
    Adaptive

然后,最后一个问题是如何让它做自己想要的事情。

感谢您从头到尾阅读所有内容,不胜感激! 如果可能的话,我必须坚持使用C ++ 98。

1 个答案:

答案 0 :(得分:0)

首先,说明为什么要获得看到的输出。

a.run呼叫adaptive.runadaptive.run首先显式调用primal::run,这将调用虚拟save函数adaptive::save

adaptive::save显式调用primal::savecommon<primal>::save)并输出“ primal :: common”。然后,我们返回到adaptive::save并输出“自适应”,然后返回到adaptive::run

现在,我们显式调用dual::runcommon<dual>::run)。这将调用虚拟save函数,该函数将再次为adaptive::save覆盖,它将复制您现有的输出。

如何解决该问题以获得所需的内容?

这取决于您的问题中没有的一些细节。这是一些可能性。

最简单的方法是从dual::save内部显式调用adaptive::save,但是我想这对您不起作用,因为dual必须先完成工作。< / p>

您可以让adaptive::save不执行任何操作,然后为save中的两个子对象调用run

您可以制作run virtual并在dual类中覆盖。