用于存储的抽象基类的替代方案
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<T>
,其中 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<Bullet*>
(或者现代c++中的std::vector<std::unique_ptr<Bullet> >
)。
然后,在您的主循环中,首先更新逻辑,然后更新物理,然后绘制子弹。
当然,由于指针解引用和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<Bullet>
,间接只会在更新逻辑时发生,但在运行物理或绘制子弹时不会发生。
【讨论】:
以上是关于用于存储的抽象基类的替代方案的主要内容,如果未能解决你的问题,请参考以下文章