doublesobig
doublesobig

Reputation: 15

C++: Find out type of custom class at runtime

I want to create a multimap that maps several bitmaps to their specific char. For latin chars there are more bitmaps (because of font size). Also I need to store chinese chars. There are different fonts (called meg5, meg7, _china01). meg-family fonts are used for latin letters and china01 is used for chinese letters. I need to be able to switch between languages. Thats why I thought of storing them all in one multima. For latin letters I need to determine correct font (between meg5 and meg7). Here are my classes:

class Bitmap {
public:
    virtual ~Bitmap() = default;
    inline std::vector<int> getBMPData() const { return m_data; }
    inline void setBMPData(std::vector<int> data) { m_data = data; }
private:
    std::vector<int> m_data;
};

class MegFamily : public Bitmap {
private:
    uint8_t m_OverallSize = 0;
    uint8_t m_xDisplacement = 0;
    uint8_t m_yDisplacement = 0;
    uint8_t m_width = 0;
    uint8_t m_height = 0;
public:
    MegFamily() {};
    inline uint8_t getOverallSize() const { return m_OverallSize; }
    inline uint8_t getXDisplacement() const { return m_xDisplacement; }
    inline uint8_t getYDisplacement() const { return m_yDisplacement; }
    inline uint8_t getWidth() const { return m_width; }
    inline uint8_t getHeight() const { return m_height; }

    //only for test purposes
    inline void setOverallSize(uint8_t overallSize) { m_OverallSize = overallSize; }
    inline void setXDisplacement(uint8_t xDisplacement) { m_xDisplacement = xDisplacement; }
    inline void setYDisplacement(uint8_t yDisplacement) { m_yDisplacement = yDisplacement; }
    inline void setWidth(uint8_t width) { m_width = width; }
    inline void setHeight(uint8_t height) { m_height = height; }
};

class Meg5 : public MegFamily {};
class Meg7 : public MegFamily {};

class ChineseFont : public Bitmap{};

I wanted to use e.g. find('A') for all A Bitmaps and then determine their font. This is what I've done so far.

    typedef std::vector<int> BMPData;
    std::multimap<char, Bitmap> BMPLibrary;

    ChineseFont SomeChineseName;
    Meg5 meg5_A;
    Meg7 meg7_A;



    BMPData BMPSomeChineseName{0x00,0x38,0x27,0x24,0x24,0x24,0x24,0x24,0x24,0xe4,0x04,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x09,0x09,0x08,0x07,0x00,0x00};

    BMPData BMPmeg5A{ 0x01, 0x15, 0x05, 0x02 };

    BMPData BMPmeg7A{ 0x7E, 0x09, 0x09, 0x09, 0x7E };

    SomeChineseName.setBMPData(BMPSomeChineseName);

    meg5_A.setBMPData(BMPmeg5A);
    meg5_A.setOverallSize(5);
    meg5_A.setXDisplacement(0);
    meg5_A.setYDisplacement(0);
    meg5_A.setWidth(4);
    meg5_A.setHeight(5);

    meg7_A.setBMPData(BMPmeg5A);
    meg7_A.setOverallSize(6);
    meg7_A.setXDisplacement(0);
    meg7_A.setYDisplacement(0);
    meg7_A.setWidth(5);
    meg7_A.setHeight(7);

    BMPLibrary.insert(std::pair<char, Bitmap>('A', meg5_A));
    BMPLibrary.insert(std::pair<char, Bitmap>('A', meg7_A));
    BMPLibrary.insert(std::pair<char, Bitmap>('\u2ed8', SomeChineseName));

    std::cout << "searching for As" << std::endl;
    auto pairFound = BMPLibrary.find('A');

    if (pairFound != BMPLibrary.end())
    {
        size_t numPairsInMap = BMPLibrary.count('A');

        for (size_t counter = 0; counter < numPairsInMap; ++counter)
        {
            std::cout << "Type of found element: " << typeid(pairFound->second).name() << std::endl;
        }
    }

My output is the following:

searching for As
Type of found element: class Bitmap
Type of found element: class Bitmap

My question is: Is it possible to determine wheter a result is instance of meg5 or meg7? Thanks for your help.

Upvotes: 0

Views: 66

Answers (2)

doublesobig
doublesobig

Reputation: 15

Thanks for your help. I changed the class definitions a bit as I think it may be more elegant

class Bitmap {
public:
    Bitmap(std::vector<int> BMPData)
        : m_data(BMPData)
    {}
    virtual ~Bitmap() = default;
    inline std::vector<int> getBMPData() const { return m_data; }
    //inline void setBMPData(std::vector<int> data) { m_data = data; }
    void printBMPData() const;
    virtual std::string name() const = 0;
protected:
    std::vector<int> m_data;
};

class MegFamily : public Bitmap {
protected:
    uint8_t m_OverallSize = 0;
    uint8_t m_xDisplacement = 0;
    uint8_t m_yDisplacement = 0;
    uint8_t m_width = 0;
    uint8_t m_height = 0;
public:
    MegFamily(uint8_t OverallSize, uint8_t xDisplacement, uint8_t yDisplacement, uint8_t width, uint8_t height, std::vector<int> BMPData)
        : m_OverallSize(OverallSize), m_xDisplacement(xDisplacement), m_yDisplacement(yDisplacement), m_width(width), m_height(height),
        Bitmap(BMPData)
    {}
    virtual void hello() const { std::cout << "MegFamily" << std::endl; }
    inline uint8_t getOverallSize() const { return m_OverallSize; }
    inline uint8_t getXDisplacement() const { return m_xDisplacement; }
    inline uint8_t getYDisplacement() const { return m_yDisplacement; }
    inline uint8_t getWidth() const { return m_width; }
    inline uint8_t getHeight() const { return m_height; }
};

class Meg5 : public MegFamily
{
public:
    virtual void hello() const { std::cout << "Meg5" << std::endl; }
    std::string name() const override { return "Meg5"; }
    Meg5(uint8_t OverallSize, uint8_t xDisplacement, uint8_t yDisplacement, uint8_t width, uint8_t height, std::vector<int> BMPData)
        : MegFamily{ OverallSize, xDisplacement, yDisplacement, width, height, BMPData} {};
    ~Meg5() {};
};
class Meg7 : public MegFamily
{
public:
    virtual void hello() const { std::cout << "Meg7" << std::endl; }
    std::string name() const override { return "Meg7"; }
    Meg7(uint8_t OverallSize, uint8_t xDisplacement, uint8_t yDisplacement, uint8_t width, uint8_t height, std::vector<int> BMPData)
        : MegFamily{ OverallSize, xDisplacement, yDisplacement, width, height, BMPData} {};
    ~Meg7() {};
};

class ChineseFont : public Bitmap
{
public:
    ChineseFont(std::vector<int> BMPData)
        : Bitmap(BMPData) {};
    std::string name() const override { return "ChineseFont"; }
};

Additionally I implemented your recommended ideas

BMPData BMPSomeChineseName{0x00,0x38,0x27,0x24,0x24,0x24,0x24,0x24,0x24,0xe4,0x04,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x09,0x09,0x08,0x07,0x00,0x00 };
BMPData BMPmeg5A{ 0x01, 0x15, 0x05, 0x02 };
BMPData BMPmeg7A{ 0x7E, 0x09, 0x09, 0x09, 0x7E };


Meg5 meg5_A = Meg5(5, 0, 0, 4, 5, BMPmeg5A);
Meg7 meg7_A = Meg7(6,0,0,5,7, BMPmeg7A);
ChineseFont SomeChineseName = ChineseFont(BMPSomeChineseName);

std::multimap<char, std::unique_ptr<Bitmap>> BMPLibrary;
    BMPLibrary.emplace('A', std::make_unique<Meg5>(std::move(meg5_A)));
    BMPLibrary.emplace('A', std::make_unique<Meg7>(std::move(meg7_A)));
    BMPLibrary.emplace('\u2ed8', std::make_unique<ChineseFont>(std::move(SomeChineseName)));

Now it's possible to determine the type at runtime. Thank you!

Upvotes: 0

mattlangford
mattlangford

Reputation: 1260

I think you have a possible option if you don't mind adding some helper functions:

class Bitmap {
    ...
public:
    virtual std::string name() const = 0;
};

...

class Meg7 : MegFamily {
    ...
public:
    std::string name() const override { return "Meg7"; }
};

Then (like some of the other comments have suggested) you'll want to change the

    std::multimap<char, Bitmap> BMPLibrary;
    ...
    BMPLibrary.insert(std::pair<char, Bitmap>('A', meg7_A));

to

    std::multimap<char, std::unqiue_ptr<Bitmap>> BMPLibrary;
    ...
    BMPLibrary.insert(std::pair<char, std::unqiue_ptr<Bitmap>>('A', std::make_unique<Meg7>(std::move(meg7_A))));
    // or you can just use emplace, which is a bit less verbose
    BMPLibrary.emplace('A', std::make_unique<Meg7>(std::move(meg7_A)));

since when you use abstract and base classes, you'll generally always need it to be a pointer to the base class, rather than just the base class.

Finally, to get the final name you can simply use:

            std::cout << "Type of found element: " << pairFound->second->name() << std::endl;

Upvotes: 1

Related Questions