Skip to main content
1 of 5

I need feedback on how to design and write this class better

I have created a template class Gallery which is intended to be used as a container for objects. I used a private member of typestd::map to maintain the collection alongside otheer functions. Be gentle, I am only a newbie.

The Gallery Class can be used to hold a map of objects that has some sort of unique identifier.
The object should implement the functions:
    const Identifier& getName();
    std::unique_ptr<LabeledObject> clone() const;
    overload: <, ==, >, and <<
*/

#ifndef GALLERY_H
#define GALLERY_H
#include <map>
#include <unordered_set>
#include <string>
#include <iostream>
#include "shape.h"

// Gallery of Objects
template<typename LabeledObject, typename Identifier> class Gallery{
public:
    /// constructors
    Gallery() = default;
    Gallery(const Gallery& galleryB);
    Gallery(Gallery&& galleryB);

    /// getters
    LabeledObject& objectCheckOut(const Identifier& name);
    const LabeledObject& viewObject(const Identifier& name) const;

    /// overloaded operators
    Gallery& operator=(const Gallery& galleryB);
    Gallery& operator=(Gallery&& galleryB);
    bool operator<(const Gallery& galleryB) const;  // compare sizes
    bool operator>(const Gallery& galleryB) const;  // compare sizes
    bool operator==(const Gallery& galleryB) const; // compare owned objects
    Gallery& operator+(const Gallery& galleryB);    // append galleryB's objects
    Gallery& operator-(const Gallery& galleryB);    // erase objects that resemble galleryB's objects
    template<typename T, typename U> friend std::ostream& operator<<(std::ostream& out, Gallery<T,U> galleryB);

    /// other utility functions
    void removeObject(const Identifier& name);
    bool isCheckedOut(const Identifier& name) const;
    bool objectExists(const Identifier& name) const;
    void objectCheckIn(const Identifier& name);
    void addObject(const LabeledObject& obj);

private:
    // boolean to show if checked out
    std::map<Identifier, std::pair<std::unique_ptr<LabeledObject>, bool>> objectsMap;

    /// private exception classes
    class GalleryException{
        private: std::string description;
        public:
            GalleryException(const std::string& description = "Exception Occurred in Gallery Class")
                : description(description){}

            const std::string& getException() const;
    };
    class ObjectCheckedOut : public GalleryException{
        public:
            ObjectCheckedOut(const std::string& description = "Object Checked Out Exception Occurred in Gallery Class")
                : GalleryException(description){}
    };
    class ObjectNotInGallery: public GalleryException{
        public:
            ObjectNotInGallery(const std::string& description = "Object Not In Gallery Exception Occurred in Gallery Class")
                : GalleryException(description){}
    };
    class ObjectNotCheckedOut: public GalleryException{
        public:
            ObjectNotCheckedOut(const std::string& description = "Object Not Checked Out Exception Occurred in Gallery Class")
                : GalleryException(description){}
    };

    /// private functions
    void appendToGallery(const Gallery& galleryB);
    static void handleException(GalleryException&&);
};

#endif

/************************************************************************************************
*************************************************************************************************
*   FUNCTION DEFINITIONS                                                                        *
*   -----------------------------                                                               *
*       Note that our class is a template hence functions are best defined within the.h file    *
*                                                                                               *
*************************************************************************************************
*************************************************************************************************/

/// constructors
    /// copy constructor
    template<typename LabeledObject, typename Identifier>
    Gallery<LabeledObject,Identifier>::Gallery(const Gallery& galleryB){
        appendToGallery(galleryB);
    }

    /// move constructor
    template<typename LabeledObject, typename Identifier>
    Gallery<LabeledObject, Identifier>::Gallery(Gallery&& galleryB)
    :objectsMap(std::move(galleryB.objectsMap)){}

/// getters
    /// viewObject
    template<typename LabeledObject, typename Identifier>
    const LabeledObject& Gallery<LabeledObject, Identifier>::viewObject(const Identifier& key) const{
        if(!objectExists(key))
            handleException(ObjectNotInGallery());
        else if(isCheckedOut(key))
            handleException(ObjectCheckedOut());

        // returning reference of unique_ptr from : [Identifier, {unique_ptr, true/false}]
        return *((objectsMap.find(key) -> second).first);
    }

    /// objectCheckOut
    template<typename LabeledObject, typename Identifier>
    LabeledObject& Gallery<LabeledObject, Identifier>::objectCheckOut(const Identifier& key){
        if(!objectExists(key))
            handleException(ObjectNotInGallery());
        else if(isCheckedOut(key))
            handleException(ObjectCheckedOut());

        // change false to true in mapElement : [Identifier, {unique_ptr, false}]
        objectsMap[key].second = true;     // label as checked out
        return *(objectsMap[key].first);
    }

/// utility functions
    /// addObject
    template<typename LabeledObject, typename Identifier>
    void Gallery<LabeledObject, Identifier>::addObject(const LabeledObject& obj){
        // new Element is in the form [Identifier, {unique_ptr, true/false}]
        objectsMap[obj.getName()] = std::make_pair(obj.clone(), false);
    }

    /// objectCheckIn
    template<typename LabeledObject, typename Identifier>
    void Gallery<LabeledObject, Identifier>::objectCheckIn(const Identifier& key){
        objectsMap[key].second = false;
    }

    /// removeObject
    template<typename LabeledObject, typename Identifier>
    void Gallery<LabeledObject, Identifier>::removeObject(const Identifier& key) {
        if(objectExists(key))
            objectsMap.erase(key);
    }

    /// isCheckedOut
    template<typename LabeledObject, typename Identifier>
    bool Gallery<LabeledObject, Identifier>::isCheckedOut(const Identifier& key) const{
        //find() returns true/false form : [Identifier, {unique_ptr, true/false}]
        return objectExists(key) && (objectsMap.find(key)-> second).second;
    }

    /// objectExists
    template<typename LabeledObject, typename Identifier>
    bool Gallery<LabeledObject, Identifier>::objectExists(const Identifier& key) const{
        return objectsMap.find(key) != objectsMap.end();
    }


/// overloaded operators
    /// assignment operator
    template<typename LabeledObject, typename Identifier>
    Gallery<LabeledObject, Identifier>& Gallery<LabeledObject, Identifier>::operator=(const Gallery& galleryB){
        if(objectsMap != galleryB.objectsMap){
            objectsMap.clear();
            appendToGallery(galleryB);
        }
        return *this;
    }

    /// move assignment
    template<typename LabeledObject, typename Identifier>
    Gallery<LabeledObject, Identifier>& Gallery<LabeledObject, Identifier>::operator=(Gallery&& galleryB){
        objectsMap = std::move(galleryB.objectsMap);
        return *this;
    }

    /// == operator
    template<typename LabeledObject, typename Identifier>
    bool Gallery<LabeledObject, Identifier>::operator==(const Gallery& galleryB) const{
        return objectsMap.size() == galleryB.objectsMap.size();
    }

    /// < operator
    template<typename LabeledObject, typename Identifier>
    bool Gallery<LabeledObject, Identifier>::operator<(const Gallery& galleryB) const{
        return objectsMap.size() < galleryB.objectsMap.size();
    }

    /// > operator
    template<typename LabeledObject, typename Identifier>
    bool Gallery<LabeledObject, Identifier>::operator>(const Gallery& galleryB) const{
        return objectsMap.size() > galleryB.objectsMap.size();
    }

    /// + operator
    template<typename LabeledObject, typename Identifier>
    Gallery<LabeledObject, Identifier>& Gallery<LabeledObject, Identifier>::operator+(const Gallery& galleryB){
        appendToGallery(galleryB);
        return *this;
    }

    /// - operator
    template<typename LabeledObject, typename Identifier>
    Gallery<LabeledObject, Identifier>& Gallery<LabeledObject, Identifier>::operator-(const Gallery& galleryB){
        for(auto it = galleryB.objectsMap.begin(); it != galleryB.objectsMap.end(); ++it)
            removeObject(it -> first);
        return *this;
    }

    /// << operator
    template<typename LabeledObject, typename Identifier>
    std::ostream& operator<<(std::ostream& out, Gallery<LabeledObject, Identifier> galleryB){
        // it points to an element in the form : [Identifier, {unique_ptr, true/false}]
        for(auto it = galleryB.objectsMap.begin(); it != galleryB.objectsMap.end(); ++it){
            std::string status = (it -> second).second ? "checked out \n" :"available \n";
            out << "This Object is " << status;
            out << ((it ->second).first) -> clone();
        }
        return out;
    }

/// private member functions
    /// appendToGallery
    template<typename LabeledObject, typename Identifier>
    void Gallery<LabeledObject, Identifier>::appendToGallery(const Gallery<LabeledObject, Identifier>& galleryB){
        // s is in the form : [Identifier, {unique_ptr, true/false}]
        for(auto s = galleryB.objectsMap.begin(); s != galleryB.objectsMap.end(); ++s)
            addObject(*((s -> second).first));
    }

    /// handleException
    template<typename LabeledObject, typename Identifier>
    void Gallery<LabeledObject, Identifier>::handleException(GalleryException&& exp){
        try{
            throw exp;
        }catch(GalleryException){
            std::cout << exp.getException();
        }
    }

/// functions of private member classes
    /// getException
    template<typename LabeledObject, typename Identifier>
    const std::string& Gallery<LabeledObject, Identifier>::GalleryException::getException() const{
        return description;
    }
```