gpt4 book ai didi

继承类的 C++ 奇怪性能

转载 作者:行者123 更新时间:2023-11-28 00:08:00 28 4
gpt4 key购买 nike

据我所知,继承层次结构中的 C++ 类中的虚函数调用应该比不从任何基类继承的等效类(即自包含类)慢一点。我决定编写一个小测试程序来查看性能差异。

我有一个由 3 个类组成的继承层次结构:Shape、Rectangle、Quadrilateral。我有一个名为 BaseQuadrilateral 的类,它不继承任何东西,并且与 Quadrilateral 类做同样的事情。每个类中有两个方法:surfaceArea() 和 volume()。我在每个类上运行一个单独的基准测试,并记录运行 10,000,000 个对象所需的时间。我预计四边形类(class)会花费更长的时间。相反,Quadrilateral 类(继承自 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();

关于继承类的 C++ 奇怪性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34467935/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com