生成一个没有虚函数的接口?
我正在编写一个游戏引擎,我已经为这个对象设置了这个类:
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 }
我在游戏中的所有类都是从SceneObjectinheritance的:
class SceneObject { public: virtual void Draw() = 0; } class Image : public SceneObject { } class Sprite : public SceneObject { } class Model3D : public SceneObject { }
所以我知道我可以为我的向量中的所有对象调用Draw()。 但我一直在优化,我试图摆脱所有的inheritance和虚函数,并使用组合,而不是内联,并且似乎是一个主要的性能问题,每个对象上执行基础。
我正在寻找一些C ++技术,我可以使用它来在我的向量中存储一堆SceneObject,然后调用Draw(),并正确地绘制与之相关的对象。 这也将用于我用作虚拟的Update()函数。
所以这个代码:
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 } }
我不认为如果我添加一个开关,或者如果/删除虚拟我会获得任何性能,所以我想弄清楚是否有一个干净的方式来处理这个问题。
有任何想法吗?
您可以使用自由函数来build模对象的drawable
方面:
#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"; } }
现在,要么使用三个单独的向量(这可能是最优的,取决于集合之间的对象之间的顺序关系?),或者考虑一个变体types向量:
1.使用变体types
#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); } }
后者的一个完整的概念certificate: 住在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.分开collections
替代使用单独的载体: 住在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); }
请注意,输出是不同的 (sorting):
drawing image drawing image drawing sprite drawing model3D
解决你的具体请愿是别人已经做的一件事。
不过,我认为你应该退后一步,考虑整个情况。 这是一个明智的举措吗? 虚拟function的任何可能的替代scheme都将引入可维护性问题,即难以修改甚至理解代码。
问题是:这真的有必要吗? 它会真的补偿吗?
虚函数涉及引用两个指针,而不是一个。 是的,这是真的,它不会被内联。 但是,我不认为这是一个真正的问题。 我确实将精力集中在algorithm级别的优化上,并在去除虚拟function之前浪费所有其他方法。
考虑到至less有一个解决scheme涉及将虚拟函数转换为常规函数(而不是成员函数),从而消除虚拟函数(即对象本身的类)与众所周知的if(if)之间的优势。
这就是说,这是你的电话。
因为你似乎有一个固定的数字types,所以似乎一个合理的方法是每个types使用一个向量,并为每个types分别应用操作:处理一系列异构对象将会造成一些中断,无论它是使用虚拟函数不是。 将各个对象如何被调用到一个函数模板的框架将会方便地处理通用性。