C ++:重型多继承层次结构的设计和成本

时间:2012-02-24 11:23:00

标签: c++ templates

我有一个包含以下三个类的类层次结构:

template<int pdim >
class Function
{
   virtual double operator()( const Point<pdim>& x) const = 0;
};

这是pdim维空间中的一个函数,返回双精度。

template<int pdim, int ldim >
class NodeFunction
{
   virtual double operator()( const Node<pdim,ldim>& pnode, const Point<ldim>& xLoc) const = 0;
};

这是来自pdim维空间中节点的ldim维局部空间的函数。

template<int pdim, int ldim, int meshdim >
class PNodeFunction
{
   virtual double operator()( const PNode<pdim,ldim,meshdim>& pnode, const Point<ldim>& xLoc) const = 0;
};
此设计的

Reason 1 :NodeFunction比Function更通用。它始终可以将本地ldim-point点映射到pdim-point。例如,边(具有ldim = 1的节点)将区间[0,1]映射到pdim维物理空间。这就是每个函数都是NodeFunction 的原因。 NodeFunction更通用,因为允许NodeFunction向Node查询属性。

此设计的

Reason 2 :PNodeFunction比NodeFunction更通用。恰好一个节点与每个PNode相关联(反之亦然)。这就是每个PNodeFunction都是NodeFunction 的原因。 PNodeFunction更通用,因为它还具有PNode的所有上下文,它是Mesh的一部分(因此它知道它的所有父节点,邻居,......)。

摘要:对于Function<pdim>的任何参数,每个NodeFunction<pdim, ldim>都是ldim。对于NodeFunction<pdim, ldim>的任何参数,每NodeFunction<pdim, ldim, meshdim> meshdimFunction

问题:在C ++中表达此问题的最佳方式是什么,以便我可以使用NodeFunction代替PNodeFunction / pdim=1,2,3,这样代码很快(它是一个高性能的计算代码),这样代码适用于

模板参数不是完全独立的,而是相互依赖: - A<dim> inherits from B<dim,dim2>(主要兴趣)但如果它也适用于最高7的pdim值,那就太好了。 - 'ldim = 0,1,...,pdim' - 'meshdim = ldim,ldim + 1,...,pdim'

要考虑性能,请注意,在程序中创建了一些函数,但多次调用它们的operator()。

变体

我想了几个实现这个的方法(我目前实现了Variant 1)。我在这里写下来,以便你可以告诉我这些方法的优点和缺点。

变式1

通过帮助程序模板Arec<dim,dim2>实现上述继承class A<dim> : public Arec<dim,dim>; class Arec<dim,dim2> : public Arec<dim,dim2-1>, public B<dim,dim2>; class Arec<dim,0> : public B<dim,dim2>; 。在伪代码中,这是

O(pdim^2)

这适用于从NodeFunction继承Function和从PNodeFunction继承NodeFunction。由于NodeFunction从PNodeFunction继承大约VerboseObject次,这是如何扩展的?这个庞大的虚拟桌面坏了吗?

注意:实际上每个函数也应该从std::cout继承,这允许我打印有关函数的调试信息,例如: PNodeFunction。我是通过VerboseObject实际上继承operator()来做到这一点的。这将如何影响性能?这应该增加构造函数和打印调试信息的时间,而不是A<dim>的时间,对吗?

变式2

不要在C ++中表达继承,例如B<dim,dim2>没有从class AHolder<dim,dim2> : public B<dim, dim> { } std::shared_pointer< AHolder<dim,dim2> > interpretAasB( std::shared_pointer< AHolder<dim> >) [...] bur继承,而是有一个转换两个

的函数
Function<dim>

我不能再使用NodeFunction<dim>来代替PNodeFunction<dim>或{{1}}了。

变体3

您最喜欢的方法是什么?

1 个答案:

答案 0 :(得分:1)

我不太了解你的问题;这可能是因为我对问题领域缺乏具体的了解。

无论如何,您似乎想要生成类的层次结构,底部是Function(大多数派生类),顶部是PNodeFunction(最少派生类)。 为此,我只能推荐Alexandrescu的Modern C ++设计书,特别是关于层次生成器的章节 这本名为Loki的书中有一个源代码库。 Here's the part that might interest you.

采用通用的元编程方式可能是最困难的,但我认为一旦设置就会导致易用性,并且与虚拟继承相比,可能会提高性能(总是要通过探查器进行验证)。

在任何情况下,我都强烈建议不要从Verbose对象继承进行日志记录,而是要有一个单独的单例记录类。
这样,您不需要类层次结构中的额外空间来存储日志记录对象 您可以只从Verbose对象继承最少的派生类,但您的函数类不记录对象;他们使用一个记录对象(我可能在这里有点迂腐)。
另一个问题是,如果从该基类继承多次,最终会得到日志对象的多个副本,并且必须使用虚拟继承来解决它。