Home Upgrade Search Memberlist Extras Hacker Tools Award Goals Help Wiki Contact

C 

Create object instance based on enumeration value

Hey folks, quick question.
Let's assume I have an Enum called 'AnimalType'. And a lot of animals inheriting from a base 'Animal' class (class Dog : public Animal).
Now, based on what 'AnimalType' I have, I want to create the corresponding derivation.

Let's assume (IDK if the shit below compiles, just writing it in HF editor):

Code
enum class AnimalType
{
DogAnimal,
CatAnimal
}

class Animal {}

class Dog : public Animal {}
class Cat : public Animal {}

I'd like to have a method that does the following:

Code
Animal* getAnimalFromEnum(AnimalType type)
{
   switch (type)
   {
        case (AnimalType::DogType):
            return new Dog()
            break;
        case (AnimalType::CatType):
            return new Cat()
            break;
   }
}

The code above will probably work, but I find it kind of silly. Especially when working with A LOT of Enum values, this is gonna get ugly.
I'd like to have a method using unordered map or something similiar. I don't know how to achieve that. Still new to C++.

Thanks for taking the time! 🤝
Using an unordered map, you can do something like this...

Code
#include <iostream>
#include <functional>
#include <unordered_map>
#include <memory>

enum class AnimalType {
    DogAnimal,
    CatAnimal
};

// Abstract class. Let's make it require a function that prints type of animal.
class Animal {
public:
    virtual void myType() = 0;
};

class Dog : public Animal {
public:
    void myType() {
        std::cout << "I'm a dog!" << std::endl;
    }
};

class Cat : public Animal {
public:
    void myType() {
        std::cout << "I'm a cat!" << std::endl;
    }
};

namespace {
    std::unordered_map<AnimalType, std::function<std::unique_ptr<Animal>()>> const animalCreators{
        { AnimalType::DogAnimal, []{ return std::make_unique<Dog>(); } },
        { AnimalType::CatAnimal, []{ return std::make_unique<Cat>(); } },
    };
}

std::unique_ptr<Animal> getAnimalFromEnum(AnimalType type) {
    return animalCreators.at(type)();
}

int main(int argc, char const *argv[]) {
    std::unique_ptr<Animal> myPet =    getAnimalFromEnum(AnimalType::DogAnimal);
    myPet->myType();
    std::unique_ptr<Animal> mySecondPet = getAnimalFromEnum(AnimalType::CatAnimal);
    mySecondPet->myType();
    return 0;
}
(May 11, 2018 02:46 PM)Annabelle Lee Wrote:  Using an unordered map, you can do something like this...

Code
#include <iostream>
#include <functional>
#include <unordered_map>
#include <memory>

enum class AnimalType {
DogAnimal,
CatAnimal
};

// Abstract class. Let's make it require a function that prints type of animal.
class Animal {
public:
virtual void myType() = 0;
};

class Dog : public Animal {
public:
void myType() {
std::cout << "I'm a dog!" << std::endl;
}
};

class Cat : public Animal {
public:
void myType() {
std::cout << "I'm a cat!" << std::endl;
}
};

namespace {
   std::unordered_map<AnimalType, std::function<std::unique_ptr<Animal>()>> const animalCreators{
       { AnimalType::DogAnimal, []{ return std::make_unique<Dog>(); } },
       { AnimalType::CatAnimal, []{ return std::make_unique<Cat>(); } },
   };
}

std::unique_ptr<Animal> getAnimalFromEnum(AnimalType type) {
   return animalCreators.at(type)();
}

int main(int argc, char const *argv[]) {
std::unique_ptr<Animal> myPet = getAnimalFromEnum(AnimalType::DogAnimal);
myPet->myType();
std::unique_ptr<Animal> mySecondPet = getAnimalFromEnum(AnimalType::CatAnimal);
mySecondPet->myType();
return 0;
}

+1 unique_ptr, +1 for at(), -1 no virtual destructor doesn't affect your code, but probably would in OP's case
OP, it's pretty much either this or a switch statement, you just gotta pick your poison since there is no runtime reflection of types in C++
(May 11, 2018 04:37 PM)Gorzoid Wrote:  +1 unique_ptr, +1 for at(), -1 no virtual destructor doesn't affect your code, but probably would in OP's case
OP, it's pretty much either this or a switch statement, you just gotta pick your poison since there is no runtime reflection of types in C++

Virtual destructor was left out on purpose, since I simply wanted to illustrate the point. Also recently discovered unique_ptr/make_unique and smart pointers, so I've been having a field day playing with them.
switch case is better than a map because with all warnings enabled the compiler will warn you if you add a new enum but forget to define a new creation method


Possibly Related Threads...
Thread / Author Replies Views Last Post
[Python] by Meelo XOMay 11, 2019 05:52 AM 0 121 May 11, 2019 05:52 AM
Last Post: Meelo XO
[C#] by itcorpJan 16, 2019 03:46 PM 7 342 Jan 16, 2019 03:46 PM
Last Post: itcorp
[Java] by deadsh0tJan 10, 2019 07:30 AM 2 170 Jan 10, 2019 07:30 AM
Last Post: deadsh0t