Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;:重多重继承层次结构的设计和成本_C++_Templates - Fatal编程技术网

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

C++ C++;:重多重继承层次结构的设计和成本,c++,templates,C++,Templates,我有一个包含以下三个类的类层次结构: template<int pdim > class Function { virtual double operator()( const Point<pdim>& x) const = 0; }; 这既适用于从NodeFunction继承函数,也适用于从PNodeFunction继承函数。由于NodeFunction从PNodeFunction继承了大约O(pdim^2)次,因此该函数如何扩展?这张巨大的虚拟桌子坏了

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

template<int pdim >
class Function
{
   virtual double operator()( const Point<pdim>& x) const = 0;
};
这既适用于从NodeFunction继承函数,也适用于从PNodeFunction继承函数。由于NodeFunction从PNodeFunction继承了大约
O(pdim^2)
次,因此该函数如何扩展?这张巨大的虚拟桌子坏了吗

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

变式2

不在C++中表示继承,例如<代码> a <代码>继承不从<代码> b/COD> BUR,而有一个函数转换两个

class AHolder<dim,dim2> : public B<dim, dim> {

}

std::shared_pointer< AHolder<dim,dim2> > interpretAasB( std::shared_pointer< AHolder<dim> >)
 [...]
类别A持有者:公共B{
}
std::shared_pointer解释器AB(std::shared_pointer)
[...]
这有一个缺点,即我不能再使用
函数
代替
节点函数
PNodeFunction

变式3
你喜欢用什么方法来实现这个问题?

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

无论如何,您似乎想要生成一个类的层次结构,函数(最派生的类)位于底部,PNodeFunction位于顶部(最派生的类)。
为此,我只能推荐Alexandrescu的现代C++设计书,特别是关于层次生成器的章节。 有一个开源库源于一本名为Loki的书。

采用通用元编程方式可能是最难的,但我认为,与虚拟继承相比,它会在安装后带来易用性,并且可能会提高性能(这总是由探查器验证)

无论如何,我强烈建议不要从Verbose对象继承日志,而是使用单独的单例日志类。
这样,您就不需要类层次结构中的额外空间来存储日志对象。

您只能从详细对象继承派生最少的类,但您的函数类不是日志对象;他们使用日志对象(我在这里可能有点迂腐)
另一个问题是,如果您多次从该基类继承,最终将得到日志对象的多个副本,并且必须使用虚拟继承来解决它。

我很难理解您的需求描述,我想在我们给你答案之前,你可能已经遗漏了一些重要的部分。特别是,如果一个
函数
是一个
节点函数
,那么这是否意味着它的
NodeFunction::operator()
将以某种方式在内部调用(“forward to”)
Function::operator()
?这里的is-a关系一点也不清楚。第二,这可能会回答你的问题:对于标准(非虚拟)继承,VTHT大小和继承深度不应该影响性能:它总是一个间接调用。最后,我在几年前做了一些HPC,它恰巧与我认为C++模板是切片面包以来最好的时间一致。所以我暗自怀疑,你想得太多了,最好是针对你的实际问题实施一个解决方案,而不是构建一个框架来构建上述解决方案。我当然可能是错的,但我建议在大多数高性能工作中坚持使用普通结构的数组/向量。@pmjordan:对于您的第一个评论。实际上,该函数通过调用
operator()(node.map(xLoc))
提供NodeFunction::operator()。这意味着它认为x和xLoc之间的关系是
x=node.map(xLoc)
@pmjordan:所以如果每个PNodeFunction都有一个虚拟继承,它来自一个类,我纯粹用于记录到控制台/文件(比如)那么这不会影响性能,除了那些虚拟继承类和构造函数中的函数,对吗?对,所以对于转发,您将支付双倍的虚拟分派价格,因为您实际上是按顺序调用2个虚拟函数。关于虚拟基类:是的,我很确定您只需为在该基类中声明的虚拟函数支付额外的费用。如果有疑问,请查看反汇编。您的意思是“3.13.使用类型列表生成类”这一节吗?我们版本的Alexandrescu的书中没有关于层次生成器的章节。如果你是这个意思,那么据我所知,这已经是我在变体1中使用的。但很高兴知道,它是以这个名字命名的。您关于从Verbose对象继承的评论很有趣,但您如何实现它呢?我确实希望有类似于虚拟函数的行为。也就是说,如果我将一个对象存储为shared_ptr,但它实际上是派生的实例,那么当我将其打印到std::out时,我希望显示派生类的信息。是的,我指的是使用类型列表生成类;它与变体1类似,不同的是您使用的是多重继承,他展示了一种单一继承的方法。对于详细对象,在这种情况下,可以使用虚拟函数“ToString”或类似函数,将日志对象作为参数传递。这样你就可以避免支付更大类的费用。Alexandrescu也使用多重继承来解决这个问题。他的方法的优点是,helper类是如此的通用,以至于我可以重用他的helper类,而不需要引入像
class Arec
这样的类。好的,我有这个虚拟的ToString方法,如果我接着多次继承类,那么我也为ToString方法分配了多次空间。作为我的父亲
template<int pdim, int ldim, int meshdim >
class PNodeFunction
{
   virtual double operator()( const PNode<pdim,ldim,meshdim>& pnode, const Point<ldim>& xLoc) const = 0;
};
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>;
class AHolder<dim,dim2> : public B<dim, dim> {

}

std::shared_pointer< AHolder<dim,dim2> > interpretAasB( std::shared_pointer< AHolder<dim> >)
 [...]