简体   繁体   中英

C++ Iterating over a list of a certain subclass

I have two classes. The superclass is a "Component" class, and the subclass is a "Transform" class.

The framework I'm using has a function that returns a list of components of a certain type. However, the list will return them as Component, since the type isn't restricted to a specific subclass (however it's the way I'm using it).

So, in the following scenario, I know that all the returned components will be of the Transform subclass. What I'm doing is I'm iterating over the list and then casting each component to Transform. Here is my code:

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 ;
}

How efficient is this? I'm quite new to C++, so I have no idea if there's a better way of doing this.

This isn't a good design, your compiler should generate a warning in this case. Normally, you should upcast your pointer using dynamic_cast. This cast has some runtime cost - aproximately the same as virtual method call but it will generate exception if you try to cast incompatible pointers. Try to redesign your app to eliminate this code. You should only call virtual methods of the Component class, you shouldn't cast pointer to Component to pointer to Transform . This thing indicate bad design.

One possible desigion is to make getComponents a template method to eliminate cast:

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

or maybe just this:

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

In a case when you can't refactor this code, you can always transform your list:

    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);

The std::list is usually implemented as double-linked list, which means that elements are scattered through the memory, which means that iterating through it is slow. Check: Why is it so slow iterating over a big std::list?

But what I would worry more about is the use of reflection:

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

that might actually be the real bottleneck of this piece of code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM