【问题标题】:Alternatives to abstract base class for storage用于存储的抽象基类的替代方案
【发布时间】:2018-06-14 21:27:35
【问题描述】:

我想知道运行时多态性的可用替代方案,特别是在我的类之间使用公共基类的替代方案,以便存储派生类的实例并与之交互。 RTP 存在通过 vtable 查找间接的缺点,并且还强制派生类存储为指针,因此通常必须动态分配它们。据我所知,这会阻碍内联和编译器优化。

简而言之,我不想要这个:

class Animal
{
public:
    virtual void noise() const = 0;
};

class Dog : public Animal
{
public:
    virtual void noise() override const {std::cout<<"Woof!\n";};
};

class Cat : public Animal
{
public:
    virtual void noise() override const {std::cout<<"Meow!\n";};
};

//...

std::vector<Animal*> animals;

我想要这样的东西:

class Dog
{
public:
    void noise() const {std::cout<<"Woof!\n";};
};

class Cat
{
public:
    void noise() const {std::cout<<"Meow!\n";};
};

//...

std::vector<*Things that have noise()*> animals;

【问题讨论】:

  • 如果您要问这样的问题,请提供与您的问题领域相关的示例,而不是这些愚蠢的动物/狗东西。
  • C++ 是一种静态类型语言。您不能有 vector&lt;T&gt; ,其中 T 不是固定类型。您可以做的最好的事情是类型擦除(请参阅std::function),但这在多态函数调度、堆分配等方面并不比基类更好。唯一真正的改进是它可以管理自己的内存。只要所涉及的类集不受限制(因此variant 不合适),您将不得不为多态调度付费。而且它不像variant 访问是免费的什么的......
  • 您提到内联是一个理想的目标,并且您提供了一个“具有噪声()的事物”的向量示例。您如何看待这项工作?承担编译器的角色。假设向量已经填充了一些东西。您无法知道那是什么,但假设我们已经检查过它是否存在。你将如何内联表达式animals[0].noise()?或者甚至在没有某种程度的间接的情况下评估该表达式?

标签: c++ polymorphism c++17 static-polymorphism


【解决方案1】:

在你的例子中,我帮不了你,但是对于有数据成员的类,这里有一个优化。

假设我们要创建一个弹幕游戏。

在一个幼稚的方法中,我们需要一个类Bullet

class Bullet {
public:
    void draw(Renderer& r);
    virtual void update_logic(float delta);
    void run_physics();
protected:
    float vx, vy; //velocity
private:
    float x, y; //position
    //...
};

因此,将调用update_logic 方法来设置子弹的速度,然后run_physics 会将这个速度应用于该位置。

修改逻辑需要多态,所以你的集合变成std::vector&lt;Bullet*&gt;(或者现代c++中的std::vector&lt;std::unique_ptr&lt;Bullet&gt; &gt;)。

然后,在您的主循环中,首先更新逻辑,然后更新物理,然后绘制子弹。

当然,由于指针解引用和vtables等,它是低效的。

你可以做的是:

class Bullet {
public:
    void draw(Renderer& r);
    void update_logic(float delta) { logic->update(delta); };
    void run_physics();
    void setVelocity(float, float);
    void setLogic(BulletLogic*);
private:
    float x, y, vx, vy;
    BulletLogic* logic;
};

所以现在,你可以使用std::vector&lt;Bullet&gt;,间接只会在更新逻辑时发生,但在运行物理或绘制子弹时不会发生。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-01-31
    • 1970-01-01
    • 1970-01-01
    • 2012-05-04
    • 2014-05-23
    • 2013-11-24
    • 2023-04-04
    相关资源
    最近更新 更多