我有一个名为WorkerA
的类,它适用于一种图像格式(我们只称它为A,它相当不标准)。该课程运作良好:
class WorkerA
{
public:
void Setup()
{
//some stuff specific to format A
}
void MainTask()
{
//some algorithm that calls GetPixel() a lot
}
//...
protected:
int GetPixel(int x, int y)
{
int value;
//value = ... (gets pixel value in format A)
return value;
}
unsigned char * pBitmapA;
//...
};
现在我需要另一个适用于图像格式B的类。MainTask
和其他一些函数与WorkerA
相同,但剩下的函数需要不同的实现。不确定这种情况下的最佳做法,我将以下内容混为一谈:
class WorkerB : public WorkerA
{
public:
void Setup()
{
//some stuff specific to format B
}
//... (other functions. MainTask not re-implemented.)
protected:
virtual int GetPixel(int x, int y)
{
int value;
//value = ... (gets pixel value in format B)
return value;
}
unsigned char ** pBitmapB; //different format than pBitmapA
};
到目前为止,我还将WorkerA::GetPixel
设为虚拟,以便在调用WorkerB::MainTask
时获得正确的多态行为。但是,这一次更改导致WorkerA::MainTask
比以前运行时间长50% - 这是我真正需要避免的。
我的问题是:我应该如何重新排列这两个类,以便尽可能少的重复代码,而没有速度惩罚?如果有必要,我可以完全重写WorkerA和WorkerB(虽然我最好能保留WorkerA的现有界面),但我不能改变图像格式。
答案 0 :(得分:5)
通常,为每个像素调用的任何成像代码都会变慢。如果可以,重构代码,使其适用于更大的块,一次可能是栅格线。
如果您可以确定在编译时使用哪个类而不是运行时,则可以使用Curiously Recurring Template Pattern (CRTP)来消除虚拟调用的开销。
答案 1 :(得分:0)
不是一个真正的答案,但这里有一些值得关注的主题。
从性能的角度来看,GetPixel()是一个出了名的坏事。认真考虑使用不需要严重依赖于此的算法。如果确实需要,可以将其转换为内联或模板或宏。
您确定基准吗?虚函数调用的固有开销是几个机器指令,通常不会造成如此严重的影响。你确定这里没有其他东西吗?
你真的需要虚拟吗?继承是许多问题的解决方案,并非所有问题都需要虚函数和动态绑定。也许你可以重新组织你的代码以使用静态继承或模板,至少在你需要的很多部分,并完全避免对GetPixel()的虚拟调用。
如果您有更多信息,请相应地修改您的问题。