生成没有虚拟函数的接口? [英] Generating an interface without virtual functions?

查看:96
本文介绍了生成没有虚拟函数的接口?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我编写一个游戏引擎,并且我为这个对象设置了这个类:

I'm coding a game engine and I have this class set up for objects:

class SceneManager //controls everything in the "world" game
{
    public:
        void Add(SceneObject* object); //adds to the vector
    private:
        vector<SceneObject*> _worldObjects; //the vector that contains all of them
}

game继承自SceneObject:

And all classes I work on the game inherit from SceneObject:

class SceneObject
{
    public: 
        virtual void Draw() = 0;
}

class Image : public SceneObject
{ }
class Sprite : public SceneObject
{ }
class Model3D : public SceneObject
{ }

所以我知道我可以为我的矢量中的所有对象调用Draw
但是我一直在做优化,我试图摆脱所有继承和虚拟函数,并使用组合代替,因为他们不能内联,似乎是一个主要的性能问题,执行时每个对象的基础。

So I know I can call Draw() for all objects in my vector. But I've been working on optimizations and I'm trying to get rid of all inheritance and virtual functions, and use composition instead, since they can't be inlined and seems to be a major performance issue when performed on a per-object basis.

我正在寻找一些C ++技术,我可以使用能够存储一堆SceneObjects在我的矢量,然后调用Draw (),它正确地绘制与它相关的对象。这也将用于我使用的虚拟的Update()函数。

I'm looking for some C++ technique that I can use to be able to store a bunch of SceneObjects in my vector, and then call Draw() on it and it properly draws the object related to it. This will also work for the Update() function I'm using as virtual.

所以这段代码:

void SceneManager::Add(SceneObject* object)
{
    _worldObjects.push_back(object);
}
void SceneManager::DrawTheWorld()
{
    for(unsigned int i = 0; i < _worldObjects.size(); i++)
    {
        _worldObjects[i]->Draw(); //SceneObject's being called
    }
}

...会变成:

void SceneManager::Add(Image* image)
{
    SceneObject* object = new SceneObject();
    //link object to image somehow, tried to use it as a member of image
    _worldObjects.push_back(object);
}
void SceneManager::DrawTheWorld()
{
    for(unsigned int i = 0; i < _worldObjects.size(); i++)
    {
        //_worldObjects[i]->
        //I need somehow to be able to get the pointer back to the original class
        //It can be an image, sprite, model3d, anything
    }
}

我不认为如果我添加一个开关或如果/ elses和删除虚拟我会获得任何

I don't think if I add a switch or if/elses and removing the virtual I'd gain any performance, so I'm trying to figure if there's a clean way to deal with this.

任何想法?

推荐答案

您可以使用自由函数为对象的 drawable 方面建模:

You can use free functions to model the drawable aspect of your objects:

#include <iostream>

class Image { };
class Sprite { };
class Model3D { };

namespace draw_aspect
{
    void draw(Image const& image)     { std::cout << "drawing image\n";   } 
    void draw(Sprite const& sprite)   { std::cout << "drawing sprite\n";  } 
    void draw(Model3D const& model3D) { std::cout << "drawing model3D\n"; } 
}






三个独立的向量(这可能是最优的,取决于集合之间的对象的排序关系),或考虑一个变体类型向量:


Now, either use three separate vectors (this could well be most optimal, depending on the ordering relationship between the objects across collections?), or consider a variant type vector:

#include <boost/variant.hpp>
using SceneObject = boost::variant<Image, Sprite, Model3D>;

namespace draw_aspect {    

    struct draw_visitor : boost::static_visitor<> {
        template <typename T> void operator()(T const& t) const { draw(t); }
    };

    void draw(SceneObject const& sobj) { 
        static const draw_visitor _vis;
        boost::apply_visitor(_vis, sobj);
    }
}

后者概念的完整证明: Live on Coliru

A complete proof of concept of the latter: Live on Coliru

#include <vector>

class SceneManager //controls everything in the "world" game
{
    public:
        void Add(SceneObject v) { _worldObjects.emplace_back(std::move(v)); }
        friend void draw(SceneManager const& sm) { return sm.draw(); }
    private:
        void draw() const {
            for(auto& sobj : _worldObjects)
                draw_aspect::draw(sobj);
        } 
        std::vector<SceneObject> _worldObjects; //the vector that contains all of them
};

int main()
{
    SceneManager sman;

    sman.Add(Image());
    sman.Add(Sprite());
    sman.Add(Model3D());
    sman.Add(Image());

    draw(sman);
}

输出

drawing image
drawing sprite
drawing model3D
drawing image



2。单独的集合



使用单独向量的替代方法: Live on Coliru

2. Separate collections

The alternative using separate vectors: Live on Coliru

class SceneManager //controls everything in the "world" game
{
    public:
        void Add(Image v)   { _images  .emplace_back(std::move(v)); }
        void Add(Sprite v)  { _sprites .emplace_back(std::move(v)); }
        void Add(Model3D v) { _model3Ds.emplace_back(std::move(v)); }

        friend void draw(SceneManager const& sm) { return sm.draw(); }
    private:
        void draw() const {
            for(auto& sobj : _images)   draw_aspect::draw(sobj);
            for(auto& sobj : _sprites)  draw_aspect::draw(sobj);
            for(auto& sobj : _model3Ds) draw_aspect::draw(sobj);
        } 
        std::vector<Image> _images;
        std::vector<Sprite> _sprites;
        std::vector<Model3D> _model3Ds;
};

int main()
{
    SceneManager sman;

    sman.Add(Image());
    sman.Add(Sprite());
    sman.Add(Model3D());
    sman.Add(Image());

    draw(sman);
}

请注意,输出是不同

drawing image
drawing image
drawing sprite
drawing model3D

这篇关于生成没有虚拟函数的接口?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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