避免嵌入式目标上的虚函数 [英] Avoiding virtual functions on embedded target

查看:22
本文介绍了避免嵌入式目标上的虚函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 class Player,它从由许多相等块组成的大内存块中播放数据.

I have a class Player that plays back data from a big block of memory that consists of a number of equal chunks.

typedef char chunk_t[100];

typedef struct {
    chunk_t data[100]
} blockOfMemory_t;

播放器本身理论上可以适用于不同的布局和数据内容,所以我想以可重用的方式对其进行编程.为此,我想到了这样的事情:

The Player itself could theoretically work for different layouts and contents of data, so I would like to program it in a re-usable way. To do this, I thought of something like this:

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;
}

通过继承并在子节点中实现数据细节,我可以实现可重用性.

By inheriting from this and implementing the data details in the child, I could achieve the re-usability.

但是,目标是 ARM Cortex-M4 处理器,速度非常重要.出于这个原因,我预计在使用虚函数时会有性能缺陷.所以我正在寻找一种方法来实现相同类型的可重用性,该方法可以在编译时解决,并允许内联 chunkHasX(..) 等.

However, the target is an ARM Cortex-M4 processor and speed is highly important. For this reason, I would expect to have performance drawbacks when using virtual functions. So I'm looking for a way to achieve the same type of re-usability with an aproach that can be resolved at compile-time and would allow for inlining of chunkHasX(..), etc.

这是尖叫的模板" - 但我该怎么做?

This is screaming "template" - but how would I do that?

谢谢!

推荐答案

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

I'm going to assume that you have measured and confirmed that the cost of virtual function calls or increased object size makes it desirable to do this. Or perhaps you just think a template design is preferable.

如果您想使用继承,您可以使用Curiously recurring template pattern (CRTP).您有一个模板化的 Player 基类,其中模板参数是派生类:

If you want to use inheritance you could use the Curiously recurring template pattern (CRTP). You have a templated Player base class where the template parameter is the derived class:

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();
}

现场演示.

或者,也许您可​​以使用组合代替继承并组合作为模板参数传递的 ChunkHolderPlayer:

Or perhaps you could use composition instead of inheritance and compose your Player of a ChunkHolder which is passed as a template parameter:

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 的评论提醒我,如果你想多态地对待这些不同的 Players,你可以.只介绍一个接口:

Update: Russ Schultz comment reminded me that if you want to treat these different Players polymorphically, you can. Just introduce an interface:

class IPlayer {
public:
  virtual ~IPlayer(){}
  virtual void play() = 0;
};

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

And then in both cases you can inherit from this interface and override the play() function:

template<class T>
class Player : IPlayer {
public:
    void play() override;
};

例如,现在您可以将播放器放在一个容器中,但不会通过在内部循环中调用虚函数来影响性能.使用 CRTP组成.

Now you can, for example, put the players in one container but you don't compromise performance by calling virtual function in inner loops. Live demo with CRTP and composition.

这篇关于避免嵌入式目标上的虚函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆