避免在嵌入式目标上使用虚函数
Avoiding virtual functions on embedded target
我有一个class Player
,它从一个由许多相等块组成的大内存块中播放数据。
typedef char chunk_t[100];
typedef struct {
chunk_t data[100]
} blockOfMemory_t;
播放器本身理论上可以为不同的布局和数据内容工作,所以我想以可重用的方式编程。为了做到这一点,我想到了这样的东西:
class Player {
public:
Player() { ... }
virtual ~Player() { ... }
void play()
{
for (int i = 0; i < getNumChunks(); i++)
{
if (chunkHasX(i) || chunkHasY(i))
playChunk(i);
}
}
protected:
virtual int getNumChunks() = 0;
virtual bool chunkHasX(int chunkIndex) = 0;
virtual bool chunkHasY(int chunkIndex) = 0;
virtual void playChunk(int chunkIndex) = 0;
}
通过继承它并在子元素中实现数据细节,我可以实现可重用性。
然而,目标是ARM Cortex-M4处理器,速度非常重要。出于这个原因,我认为在使用虚拟函数时会出现性能缺陷。因此,我正在寻找一种方法来实现相同类型的可重用性,这种方法可以在编译时解决,并允许内联chunkHasX(..)
等。
这是尖叫"模板"-但我怎么做呢?
谢谢!
我将假设您已经测量并确认了虚函数调用的成本或对象大小的增加使得需要这样做。或者你只是认为模板设计更可取。
与CRTP的继承
如果您想使用继承,您可以使用好奇循环模板模式(CRTP)。你有一个模板化的Player基类,其中模板参数是派生类:
template<class Derived>
class Player {
public:
void play()
{
auto& derived = static_cast<Derived&>(*this);
for (int i = 0; i < derived.getNumChunks(); i++)
{
if (derived.chunkHasX(i) || derived.chunkHasY(i))
derived.playChunk(i);
}
}
};
class DerivedPlayer : public Player<DerivedPlayer> {
private:
friend class Player<DerivedPlayer>;
int getNumChunks();
bool chunkHasX(int chunkIndex);
bool chunkHasY(int chunkIndex);
void playChunk(int chunkIndex);
};
int main() {
DerivedPlayer p;
p.play();
}
现场演示。
作文
或者您可以使用组合而不是继承,并将作为模板参数传递的ChunkHolder
组成您的Player
:
template<class ChunkHolder>
class Player {
private:
ChunkHolder chunk_holder;
public:
void play()
{
for (int i = 0; i < chunk_holder.getNumChunks(); i++)
{
if (chunk_holder.chunkHasX(i) || chunk_holder.chunkHasY(i))
chunk_holder.playChunk(i);
}
}
};
class MyChunkHolder {
public:
int getNumChunks();
bool chunkHasX(int chunkIndex);
bool chunkHasY(int chunkIndex);
void playChunk(int chunkIndex);
};
int main() {
Player<MyChunkHolder> p;
p.play();
}
现场演示。
更新:Russ Schultz的评论提醒我,如果你想以多态的方式对待这些不同的玩家,你可以这么做。只需引入一个接口:
class IPlayer {
public:
virtual ~IPlayer(){}
virtual void play() = 0;
};
然后在这两种情况下,您都可以继承这个接口并覆盖play()
函数:
template<class T>
class Player : IPlayer {
public:
void play() override;
};
现在你可以,例如,把播放器放在一个容器中,但你不会因为在内循环中调用虚函数而影响性能。
与静态函数相比,调用虚函数的代价最多是一次查找。
每个对象都有一个指针指向它的虚函数表,虚函数表中有虚函数指针,所以它类似于:
ldr [r0,#8],r4
blx r4
代替
ldr #0x400025e5,r4
blx r4
或
(如果需要分支的地址可以内联编码)br #0x1035
只要不是在紧循环中调用虚函数,这就不是问题。
相关文章:
- 线性优化目标函数中的绝对值
- 字符串函数在目标C++上运行时C++返回空
- 目标是找到两个 c 字符串之间的公共前缀(必须使用特定的函数标头)
- 为什么即使链接器找到目标文件,我的程序也看不到函数定义?
- 从.o目标文件中提取函数的原始机器代码?
- Google Mock:在目标类的构造函数中实例化的模拟私有变量成员
- Cgal二次规划目标函数
- linux 是否"rename"函数调用块,直到复制(当源和目标在不同磁盘中时)完成
- C++ lambda 函数 - 如何返回与目标相比最接近的矢量元素
- 一个函数怎么能完成它的目标,只是在返回主函数后崩溃?
- 将参数转换为目标类型时,复制用于直接初始化的构造函数省略
- 如何从std ::函数中提取和执行目标
- 我有一个构造函数,但我需要将输出返回到 main.cpp.我无法使用获取字符串功能!!任何想法如何实现这一目标?
- Turbo C++:为 malloc 函数生成目标代码
- 如何创建一个qmake函数来创建一个自定义的make目标
- 在目标函数中使用迭代器的 STL 算法
- 外部"C"已编译目标代码中的函数
- 没有用于初始化 - C++ 和目标 C 的匹配构造函数
- 就地构造 std::函数目标
- C++0x:std::函数::目标和模板参数错误