我为无法解释的以下行为感到困惑。我试图写一个有意义的标题,但不确定是否钉上了它。
首先有一些背景知识。
我编写了数值模拟软件,并尝试对代码进行一些现代化。我有三个数值解算器:primal
,dual
和adaptive
。
primal
求解器在工作时不知道其他任何事情。 dual
求解器与primal
有很多共同点,但从未单独使用,adaptive
求解器是一个包含并运行primal
和{{ 1}},按此顺序。
现在,问题是,当dual
求解器运行其adaptive
求解器时,与单独使用时相比,primal
需要执行一些其他操作。让这样的操作之一为primal
。另外,save
和primal
有很多共同点,所以我认为它们应该在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;
}
在我看来,这意味着
Primal
Adaptive
Dual
呼叫a.run
primal::run = common<primal>::run
调用common<primal>::run
,但是此方法为primal::save
,因此它解析为调用virtual
adaptive::save
显式调用adaptive::save
,因为我希望它执行primal::save
的常规任务以及其他操作primal
做其他工作并返回adaptive::save
调用a.run
,后者调用dual::run = common<dual>::run
,但是此方法不是 dual::save
,因此选择时忽略了virtual
。到目前为止一切都很好,这正是我想要的。 因此,第一个问题:以上所有方法正确吗?
现在,问题来了。
经过一些重构后,adaptive::save
和primal::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。
答案 0 :(得分:0)
首先,说明为什么要获得看到的输出。
a.run
呼叫adaptive.run
。 adaptive.run
首先显式调用primal::run
,这将调用虚拟save
函数adaptive::save
。
adaptive::save
显式调用primal::save
(common<primal>::save
)并输出“ primal :: common”。然后,我们返回到adaptive::save
并输出“自适应”,然后返回到adaptive::run
。
现在,我们显式调用dual::run
(common<dual>::run
)。这将调用虚拟save
函数,该函数将再次为adaptive::save
覆盖,它将复制您现有的输出。
如何解决该问题以获得所需的内容?
这取决于您的问题中没有的一些细节。这是一些可能性。
最简单的方法是从dual::save
内部显式调用adaptive::save
,但是我想这对您不起作用,因为dual
必须先完成工作。< / p>
您可以让adaptive::save
不执行任何操作,然后为save
中的两个子对象调用run
。
您可以制作run
virtual
并在dual
类中覆盖。