用于存储的抽象基类的替代方案

Posted

技术标签:

【中文标题】用于存储的抽象基类的替代方案【英文标题】: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;

【问题讨论】:

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

【讨论】:

以上是关于用于存储的抽象基类的替代方案的主要内容,如果未能解决你的问题,请参考以下文章

记录抽象基类的属性?

App Engine 的替代/兼容数据存储?

为多态基类声明一个虚析构函数

使用具有抽象基类指针并调用派生类函数的映射

虚拟基类是如何存储的?

抽象类