[英]C++ strange performance with inherited class
据我了解,在继承层次结构中C ++类中的虚函数调用应该比不从任何基类继承的等效类(即自包含类)慢一些。 我决定编写一个小型测试程序,以查看性能差异。
我有一个由3个类组成的继承层次结构:Shape,Rectangle,Quadrilateral。 我有一个称为BaseQuadrilateral的类,该类不继承任何东西,并且具有与Quadrilateral类相同的功能。 每个类中有两种方法:surfaceArea()和volume()。 我在每个类上运行单独的基准测试,并记录运行10,000,000个对象所需的时间。 我预计四边形课程将花费更长的时间。 相反,四边形类(继承自Rectangle)运行并比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 Test\n" << 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
。 但是,这并不能解释您所观察到的差异。 为此,您应该仔细查看两个测试循环,尤其是它们之间的区别。
在第一种情况下,您将以可变的shape
记录指向Quadrilateral
的指针,然后通过该指针间接调用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;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.