首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >避免嵌入式目标上的虚拟函数

避免嵌入式目标上的虚拟函数
EN

Stack Overflow用户
提问于 2015-09-09 11:39:02
回答 2查看 2.8K关注 0票数 3

我有一个class Player,它可以回放由大量相等块组成的大内存块中的数据。

代码语言:javascript
复制
typedef char chunk_t[100];

typedef struct {
    chunk_t data[100]
} blockOfMemory_t;

从理论上讲,播放器本身可以处理不同的布局和数据内容,所以我想以一种可重用的方式对其进行编程。为了做到这一点,我想到了这样的事情:

代码语言:javascript
复制
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皮质M4处理器和速度是非常重要的。因此,我希望在使用虚拟函数时会出现性能缺陷。因此,我正在寻找一种方法来实现相同类型的可重用性,它可以在编译时解析,并允许chunkHasX(..)的内联,等等。

这是尖叫的“模板”-但我该怎么做呢?

谢谢!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-09-09 15:21:26

我将假设您已经测量并确认了虚拟函数调用或增加对象大小的成本使得这样做是可取的。或者你只是觉得模板设计更好。

用CRTP进行继承

如果要使用继承,可以使用奇怪的是反复出现的模板模式(CRTP)。您有一个模板播放器基类,其中模板参数是派生类:

代码语言:javascript
复制
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();
}

现场演示

作文

或者您可以使用组合而不是继承,并编写作为模板参数传递的PlayerChunkHolder

代码语言:javascript
复制
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的评论提醒我,如果你想从形式上对待这些不同的球员,你可以。只需引入一个接口:

代码语言:javascript
复制
class IPlayer {
public:
  virtual ~IPlayer(){}
  virtual void play() = 0;
};

然后,在这两种情况下,您可以从这个接口继承并覆盖play()函数:

代码语言:javascript
复制
template<class T>
class Player : IPlayer {
public:
    void play() override;
};

例如,现在可以将播放器放在一个容器中,但是在内部循环中调用虚拟函数不会影响性能。现场演示与CRTP作文

票数 7
EN

Stack Overflow用户

发布于 2015-09-09 13:08:04

调用虚拟函数与静态函数的成本在最坏的情况下是一次查找。

每个对象都有一个指向它的vtable的指针,其中包含虚拟函数指针,所以如下所示:

代码语言:javascript
复制
ldr [r0,#8],r4 
blx r4

而不是

代码语言:javascript
复制
ldr #0x400025e5,r4
blx r4

或者(如果您需要分支的地址可以内联编码)

代码语言:javascript
复制
br #0x1035

只要您不是在紧循环中调用虚拟函数,它就不是一个问题。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32478555

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档