简体   繁体   中英

C++ how to loop through different types

Let's say I have a Light class, and also SpotLight , PointLight and DirectionalLight which inherits from Light .

I have a map of Lights like this : std::map<std::string, Light*> LightMap;

I'd like to iterate this map for each type like this:

for ( /* each SpotLight* in LightMap */ ) { ... }

for ( /* each PointLight* in LightMap */) { ... }

etc...

How can I do that ?

You can't, you'd have to iterate through each item and cast for the class type you want.

for(std::map<std::string, Light*>::iterator iter = m.begin(); iter != m.end(); iter++)
{
    if (dynamic_cast<SpotLight*>(*iter))
    {
    }
}

To avoid using dynamic cast, you could also add functions to your Light class like 'IsSpotLight' which can be overloaded by the SpotLight class to return true, etc.

You could also make separate maps for each type of light so if you need just spot lights, use the SpotLightMap mapping.

You can use dynamic_cast and a polymorphic base class to determine which type of light you're dealing with:

#include <map>
#include <string>
#include <iostream>

class Light { public: virtual ~Light(){} }; // Light is polymorphic
class SpotLight : public Light {};
class PointLight : public Light {};
class DirectionalLight : public Light {};


int main() {
    using namespace std;
    map<string, Light*> lightmap;

    for (const auto& light : lightmap) {
        if (SpotLight* spot = dynamic_cast<SpotLight*>(light.second))
            cout << light.first << " is a spot light" << endl;
        else if (PointLight* point = dynamic_cast<PointLight*>(light.second))
            cout << light.first << " is a point light" << endl;
        else if (DirectionalLight* point = dynamic_cast<DirectionalLight*>(light.second))
            cout << light.first << " is a directional light" << endl;
        else
            cout << light.first << " is an unknown light" << endl;
    }
}

I have written some code that will solve your requirement.

class Light {
    typedef enum {SpotLight, PointLight, DirectionalLight} LightTypeT;
    LightTypeT GetLightType() = 0;
};

class SpotLight : public Light {
    LightTypeT GetLightType() { return SpotLight; }
};


class PointLight : public Light {
    LightTypeT GetLightType() { return PointLight; }
};


class DirectionalLight : public Light {
    LightTypeT GetLightType() { return DirectionalLight; }
};

typedef std::map<std::string, Light*> LightMapT;

LightMapT::iterator be = light_map.begin(),
                    en = light_map.end();

for (; be != en; be++)
{
    Light * m_light = (*be).second;
    switch (m_light->GetLightType())
    {
        case SpotLight :
            {
                 // It is SpotLight
                 break;
            }
        case PointLight :
            {
                // It is PointLight
                break;
            }

        case DirectionalLight :
            {
                // It is DirectionalLight
                break;
            }
     }
}

Please let me know if it does not solve your problem. We will work on that

What about something like

for ( /*each Light* lit in LightMap*/)
{
    //if lit is instance of Spotlight, do something

}

for ( /*each Light* lit in LightMap*/)
{
    //if lit is instance of PointLight, do something

}

For the C++ version of instanceof , see here

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