我在使用C ++编写大型包时相对较新,因此我并不完全熟悉该语言中的一些OOP技术。
我正在开发一个代码,可以运行模拟来计算各种模型框架内材料的变形。我有一个总体Sim
课程,其中包含set_boundary_conditions()
,update_grid()
,solve()
等方法。
我想将各种模型实现为派生类。例如,如果您只想考虑线性弹性方程,ElasticSim
可塑性等等,我会得到一个Sim
类,它来自PlasticSim
。
因为模型定义了必须求解的方程式,它进入了update_grid()
函数,所以我已经update_grid()
virtual
,因此可以针对每个模型实现不同的方法。此外,set_boundary_conditions()
更具体 - 给定模型中的不同模拟将具有不同的边界条件,因此在virtual
和任何派生类中都应该Sim
。将会有另一个派生类,它实现给定物理情况的边界条件。
这可能过于复杂,但我认为这是一种非常模块化和通用的方法来解决这个问题。但我离题了。我有一个重要问题。
首先,solve()
方法对于每个模型都是相同的。因此,我想在Sim
中定义它。但是,它调用virtual
函数,稍后将由派生类实现。也就是说,在伪代码和c ++的混合中:
Sim::set_boundary_conditions()
for every time step...
Sim::update_grid()
在我能够正确测试之前会有相当多的编码,我无法在线找到合适的答案。这真的有意义吗?特别是,我正在调用Sim::update_grid()
和Sim::set_boundary_conditions()
,尽管这些函数实际上将分别在派生类和派生类的派生类中实现。
答案 0 :(得分:2)
这实际上有意义吗?
是的,Sim::solve
非虚拟和调用虚拟功能完全没问题。只有你必须注意虚拟调用的情况才在构造函数和析构函数中(因为vtable可能尚未完全形成或者可能已被破坏)。
在某些时候可能对您有用的习惯用语是NVI(非虚拟接口)。该想法包括对公共接口使用非虚方法,对受保护/私有方法使用虚方法。这个想法是允许集中控制,但仍然允许某些部分的可覆盖性。例如:
class Foo
{
public:
virtual ~Foo() {}
// public non-virtual interface: calls virtual interface.
void do_something()
{
// Can add central stuff here that affects the
// entire hierarchy at any given time.
do_something_impl();
}
private:
// subclasses can override this part.
virtual void do_something_impl() = 0;
};
这种设计留下了摆动空间来做一些集中适用于整个层次结构的事情(在远见或后见之明),同时允许子类部分覆盖行为并导致新的代码子分支。
然而,你在基类中调用虚拟方法定义的这个中心sim
方法有什么用。这将使它成为混合具体实现和可覆盖接口的抽象基类,而不是没有任何具体实现的纯虚拟接口,例如,同样,值得注意的是,您可以为虚函数提供默认实现 - 并非基类中的所有方法都不需要是纯虚函数,甚至根本不需要虚函数。