c++ - 用于存储的抽象基类的替代方案
问题描述
我想知道运行时多态性的可用替代方案,特别是在我的类之间使用公共基类的替代方案,以便存储派生类的实例并与之交互。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;
解决方案
在您的示例中,我无法帮助您,但是对于具有数据成员的类,这里有一个优化。
假设我们要创建一个弹幕游戏。
在一种天真的方法中,我们需要一个类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*>
(或std::vector<std::unique_ptr<Bullet> >
在现代 c++ 中)。
然后,在您的主循环中,首先更新逻辑,然后更新物理,然后绘制子弹。
当然,由于指针取消引用和 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>
,并且仅在更新逻辑时才会发生间接,但在运行物理或绘制子弹时不会发生。
推荐阅读
- firebase - 如何从管理员部分更改 Firebase 密码
- r - 仅基于两列 Rstudio 从长格式到宽格式
- python - Python:如何从 AWS S3 读取和加载 excel 文件?
- model-view-controller - MVC 应用程序中调用的持久对象是什么?
- python-2.7 - ImportError:无法导入名称游戏
- java - 获取色轮java中两种颜色之间的差异
- hbase - 如何从 Geomesa 中的 hbase 批量获取数据?
- python - python中单个子列表的长度
- json - 如何使用 Bash 创建具有来自许多文件的同一行的值的数组?
- c# - 有没有办法绑定到像文件夹结构一样具有可变数量级别的 UWP TreeView?