【问题标题】:C++ Iterating over a list of a certain subclassC ++迭代某个子类的列表
【发布时间】:2013-11-03 12:44:42
【问题描述】:

我有两节课。超类是“组件”类,子类是“变换”类。

我使用的框架有一个函数,它返回特定类型的组件列表。但是,列表会将它们作为组件返回,因为类型不限于特定的子类(但这是我使用它的方式)。

因此,在以下场景中,我知道所有返回的组件都将属于 Transform 子类。我正在做的是遍历列表,然后将每个组件转换为 Transform。这是我的代码:

std::list<Cistron::Component*,std::allocator<Cistron::Component*>> playerTransforms = objectManager->getComponents(player,"Transform");
std::list<Cistron::Component*>::iterator playerComponentIterator = playerTransforms.begin();
for (playerComponentIterator; playerComponentIterator != playerTransforms.end(); playerComponentIterator++)
{
    Transform *tmpTransform = static_cast<Transform*> (*playerComponentIterator);
    std::cout << tmpTransform->x ;
    std::cout << tmpTransform->y ;
}

这效率如何?我对 C++ 很陌生,所以我不知道是否有更好的方法。

【问题讨论】:

    标签: c++ list casting iterator subclass


    【解决方案1】:

    这不是一个好的设计,您的编译器应该在这种情况下生成警告。通常,您应该使用 dynamic_cast 向上转换您的指针。这种转换有一些运行时成本 - 与虚拟方法调用大致相同,但如果您尝试转换不兼容的指针,它将产生异常。 尝试重新设计您的应用程序以消除此代码。你应该只调用Component类的虚方法,你不应该将指向Component的指针转换为指向Transform的指针。这东西表明设计不好。

    一种可能的设计是使getComponents 成为消除强制转换的模板方法:

    template<class T>
    list<T*> getComponents(Player* player, std::string name) {
        ...
    }
    

    或者也许只是这样:

    list<Transform*> getTransfromComponents(Player* player) {...}
    

    如果您无法重构此代码,您可以随时转换您的列表:

        list<Component*> rlist = ...
        list<Transform*> llist;
        // Upcast all
        transform(rlist.begin(), 
                  rlist.end(), 
                  back_inserter(llist), 
                  [](Component* r) {
                      return dynamic_cast<Transform*>(r);
        });
        // Remove all null values
        llist.remove(nullptr);
    

    【讨论】:

    • 尝试强制转换不兼容的指针将返回空指针。尝试强制转换不兼容的引用将引发异常。
    • 好点!但我不记得上次我什么时候需要在实际代码中使用 dynamic_cast 了,反正:)
    • 假设我有大约 20 个 Component 子类,每个子类都有自己的函数和变量。这不会导致一个臃肿的基类充满不需要的东西吗?
    • 这会导致代码膨胀,我的意思是你需要重新设计你的应用程序来限制强制转换的需要。您的查询从对象转换,但您的方法返回指向某个基类的指针。为什么不*无效? :)
    • 方法不是我做的。它在我正在使用的图书馆中。 (西斯龙)
    【解决方案2】:

    std::list 通常实现为双链表,这意味着元素分散在内存中,这意味着遍历它很慢。检查:Why is it so slow iterating over a big std::list?

    但我更担心的是反射的使用:

    objectManager->getComponents(player,"Transform");
    

    这实际上可能是这段代码的真正瓶颈。

    【讨论】:

    • 你说得对,这是一个瓶颈。 Unity3D 中有一个类似的功能,他们在那里警告它的性能成本。但是框架只提供了这种方法来检索这种情况下的组件。
    猜你喜欢
    • 2015-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-06
    • 2019-05-25
    • 2023-03-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多