c ++中深度继承树的性能影响

Seg*_*ult 8 c++ performance inheritance

是否存在与深度继承树(在c ++中)相关的任何效率缺点,即,一大组类A,B,C等,使得B扩展A,C扩展B,等等.我能想到的一个效率含义是,当我们实例化最底层的类时,比如C,那么也会调用B和A的构造函数,这将具有性能影响.

Nic*_*las 13

让我们列举一下我们应该考虑的操作:

建筑/销毁

每个构造函数/析构函数都将调用其基类等价物.然而,正如James McNellis指出的那样,无论如何你显然都会做这项工作.你没有从A派生,因为它就在那里.所以这项工作将以某种方式完成.

是的,它将涉及更多的函数调用.但是,与实际工作相比,函数调用开销将无关紧要,任何深层次的层次结构都必须实际执行.如果你正处于函数调用开销对性能实际上很重要的地步,我强烈建议调用构造函数可能不是你想要在那个代码中做的.

对象大小

通常,派生类的开销是空的.虚拟成员的开销是指针或虚拟继承.

成员函数调用,静态

这样,我的意思是调用非虚方法成员函数,或者使用类名称调用虚拟成员函数(ClassName :: FunctionName语法).这两个都允许编译器在编译时知道要调用哪个函数.

这种性能与层次结构的大小不变,因为它是编译时确定的.

成员函数调用,动态

这是对运行时调用的完全和完全期望的虚函数调用.

在大多数理智的C++实现中,这与对象层次结构的大小不变.大多数实现为每个类使用v表.每个对象都有一个v表指针作为成员.对于任何特定的动态调用,编译器访问v表指针,选择方法并调用它.由于v-table对于每个类都是相同的,因此对于具有深层次结构的类而言,对于具有浅层的类而言,它不会更慢.

虚拟继承与此有关.

指针演员,静态

这指的是static_cast任何等效的操作.这意味着从派生类到基类的隐static_cast式转换,显式使用或C样式转换等.

请注意,这在技术上包括参考铸造.

类之间(向上或向下)的静态强制转换的性能与层次结构的大小不变.任何指针偏移都将是编译时生成的.这应该适用于虚拟继承以及非虚拟继承,但我并非100%肯定.

指针演员,动态

这显然是指明确使用dynamic_cast.这通常在从基类转换为派生类时使用.

dynamic_cast对于大型层次结构,性能可能会发生变化.但是,理智的实现应该只检查当前类和所请求的类之间的类.因此,它在两者之间的类数中是线性的,而不是层次结构中类的数量的线性.

类型

这意味着使用typeof运算符来获取与std::type_info对象关联的对象.

其性能将与层次结构的大小不变.如果类是虚拟类(具有虚函数或虚基类),那么它只是将它从vtable中拉出来.如果它不是虚拟的,那么它是编译时定义的.

结论

简而言之,大多数操作与层次结构的大小不变.但即使在有影响的情况下,也不是问题.

我更关心一些设计伦理,你觉得有必要建立这样的层次结构.根据我的经验,这样的等级制度来自两个设计线.

  1. Java/C#理想的所有内容都来自一个公共基类.这在C++中是一个可怕的想法,永远不应该使用.每个对象应该来自它所需要的东西,而且只有它.C++建立在"为你使用的东西付费"原则的基础上,并从一个共同的基础推导出来.一般来说,你可以用这种公共基类做的任何事情都是你不应该做的事情,或者可以用函数重载完成的事情(operator<<例如,使用转换为字符串).

  2. 滥用继承权.在应该使用包含时使用继承.继承在对象之间创建"是一种"关系.通常情况下,"有一个"关系(一个对象有另一个对象作为成员)更有用和灵活.它们使隐藏数据变得更容易,并且您不允许用户假装一个类是另一个类.

确保您的设计不会违反其中一项原则.