C++具有继承类的奇怪性能
C++ strange performance with inherited class
据我所知,继承层次结构中C++类中的虚拟函数调用应该比不从任何基类继承的等价类(即自包含类)慢一点。我决定写一个小的测试程序,看看性能上有什么不同。
我有一个由3个类组成的继承层次结构:形状,矩形,四边形。我有一个名为BaseQuadrilateral的类,它不继承任何东西,并且做与Quadrilateal类相同的事情。每个类中有两个方法:surfaceArea()和volume()。我在每个类上运行一个单独的基准测试,并记录运行10000000个对象所需的时间。我预计四边形课程会花更长的时间。相反,四边形类(从矩形继承)的运行速度和数量级都比BaseQuadrilateral快。我不明白为什么会这样。
Test Results:
Running Dynamic Dispatch Test
Quadrilateral Runtime: 2840264 Ticks, 2 Seconds.
BaseQuadrilateral Runtime: 21179219 Ticks, 21 Seconds.
有人能向我解释一下,是什么让继承的代码更快,在什么情况下继承的代码会比非继承的代码运行得慢。
谢谢
class Shape
{
public:
virtual double surfaceArea() = 0;
virtual double Volume() = 0;
};
class Rectangle : public Shape
{
public:
//Constructors
Rectangle();
Rectangle(double, double);
Rectangle(const Rectangle&);
Rectangle& operator=(const Rectangle&);
double Area();
//Override Shape base class methods
double surfaceArea();
double Volume();
protected:
double length;
double width;
};
class Quadrilateral : public Rectangle
{
public:
//Constructors
Quadrilateral();
Quadrilateral(double, double, double);
Quadrilateral(const Quadrilateral&);
Quadrilateral& operator=(const Quadrilateral&);
//Overloaded Square base class
double surfaceArea();
double Volume();
protected:
double height;
};
class BaseQuadrilateral
{
public:
//Constructors
BaseQuadrilateral();
BaseQuadrilateral(double, double, double);
BaseQuadrilateral(const BaseQuadrilateral&);
BaseQuadrilateral& operator=(const BaseQuadrilateral&);
double surfaceArea();
double Volume();
protected:
double length;
double width;
double height;
};
void test2()
{
clock_t qTimer, bqTimer;
Quadrilateral* quadrilaterals;
BaseQuadrilateral* baseQuadrilaterals, baseQuadrilateral;
Shape* shape;
double* answers1, *answers2;
srand((unsigned int)time(NULL));
cout << "Running Dynamic Dispatch Testn" << endl;
quadrilaterals = new Quadrilateral[ARRAY_SIZE];
baseQuadrilaterals = new BaseQuadrilateral[ARRAY_SIZE];
answers1 = new double[ARRAY_SIZE];
answers2 = new double[ARRAY_SIZE];
//Initialization
for (int i = 0; i < ARRAY_SIZE; i++)
{
double length = (double)(rand() % 100);
double width = (double)(rand() % 100);
double height = (double)(rand() % 100);
quadrilaterals[i] = Quadrilateral(length, width, height);
baseQuadrilaterals[i] = BaseQuadrilateral(length, width, height);
}
//Test Shape
qTimer = clock();
for (int i = 0; i < ARRAY_SIZE; i++)
{
shape = &quadrilaterals[i];
answers1[i] = shape->Volume();
}
qTimer = clock() - qTimer;
//Test BaseQuadrilateral
bqTimer = clock();
for (int i = 0; i < ARRAY_SIZE; i++)
{
baseQuadrilateral = baseQuadrilaterals[i];
answers2[i] = baseQuadrilateral.Volume();
}
bqTimer = clock() - qTimer;
for (int i = 0; i < ARRAY_SIZE; i++)
{
if (answers1[i] != answers2[i])
{
cout << "Incorrect answer found at i=" << i << ". answers1: " << answers1[i] << " answers2: " << answers2[i] << endl;
break;
}
}
//Print Results
cout << "Quadrilateral Runtime: " << qTimer << " Ticks, " << qTimer / CLOCKS_PER_SEC << " Seconds." << endl;
cout << "BaseQuadrilateral Runtime: " << bqTimer << " Ticks, " << bqTimer / CLOCKS_PER_SEC << " Seconds." << endl;
}
正如我在评论中所写的,您对这一行有点问题:
bqTimer = clock() - qTimer;
您似乎希望qTimer
为bqTimer
。然而,这并不能解释你所观察到的巨大差异。为此,您应该仔细查看您的两个测试循环,特别是它们之间的差异。
在第一种情况下,将指向Quadrilateral
的指针记录在变量shape
中,然后通过指针间接调用Volume()
方法:
for (int i = 0; i < ARRAY_SIZE; i++)
{
shape = &quadrilaterals[i];
answers1[i] = shape->Volume();
}
在第二种情况下,您正在制作整个BaseQuadrilateral
对象的副本,然后调用副本的Volume()
方法:
for (int i = 0; i < ARRAY_SIZE; i++)
{
baseQuadrilateral = baseQuadrilaterals[i];
answers2[i] = baseQuadrilateral.Volume();
}
复制一个对象比获取其地址要贵得多。事实上,在这种特殊情况下,地址计算甚至可能被完全优化掉。我建议避免中介,在这两种情况下都直接在数组元素上调用方法:
answers1[i] = quadrilaterals[i].Volume();
或
answers2[i] = baseQuadrilaterals[i].Volume();
该行是否应
bqTimer = clock() - qTimer;
是
bqTimer = clock() - bqTimer;
相关文章:
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- 继承函数的重载解析
- OpenMP阵列性能较差
- 继承期间显示未知行为的子类
- 递归列出所有目录中的C++与Python与Ruby的性能
- 头文件-继承c++
- 为什么在保护模式下继承升级不起作用
- 通过继承类使用来自不同命名空间的运算符
- 子目录是否继承属性,例如add_definitions,include_directories和父Cmakelist.t
- 大小相等但成员数量不同的结构之间的性能差异
- 混合组合和继承的C++问题
- 继承:构造函数,初始化C++11中基类的类C数组成员
- 虚拟继承的性能开销(如果只有一个基具有数据成员)
- 在C++中使用指针列表(继承还是性能?
- 从抽象类继承的抽象方法是否存在任何性能问题
- C++:继承和模板性能权衡
- C++具有继承类的奇怪性能
- c++中继承(is-a)与聚合(has-a)对性能的影响
- 声明成员是静态的还是非静态的?使用虚拟继承的性能
- 这样的继承对性能的影响是什么?