mercredi 21 novembre 2018

What is the purpose of having such complicated C++ class design?

I came across an open source C++ code and I got curious, why do people design the classes this way?

So first things first, here is the Abstract class:

class BaseMapServer
    {
    public:
        virtual ~BaseMapServer(){}

        virtual void LoadMapInfoFromFile(const std::string &file_name) = 0;
        virtual void LoadMapFromFile(const std::string &map_name) = 0;
        virtual void PublishMap() = 0;
        virtual void SetMap() = 0;
        virtual void ConnectROS() = 0;
    };

Nothing special here and having an abstract class can have several well understood reasons. So from this point, I thought maybe author wanted to share common features among other classes. So here is the next class, which is a seperate class but actually holds a pointer of type abstract class mentioned above (actual cpp file, other two classes are header files) :

class MapFactory
{
    BaseMapServer *CreateMap(
            const std::string &map_type,
            rclcpp::Node::SharedPtr node, const std::string &file_name)
        {
            if (map_type == "occupancy") return new OccGridServer(node, file_name);
            else
            {
                RCLCPP_ERROR(node->get_logger(), "map_factory.cpp 15: Cannot load map %s of type %s", file_name.c_str(), map_type.c_str());
                throw std::runtime_error("Map type not supported")
            }
        }
};

And now the interesting thing comes, here is the child class of the abstract class:

class OccGridServer : public BaseMapServer
    {
    public:
        explicit OccGridServer(rclcpp::Node::SharedPtr node) : node_(node) {}
        OccGridServer(rclcpp::Node::SharedPtr node, std::string file_name);
        OccGridServer(){}
        ~OccGridServer(){}

        virtual void LoadMapInfoFromFile(const std::string &file_name);
        virtual void LoadMapFromFile(const std::string &map_name);
        virtual void PublishMap();
        virtual void SetMap();
        virtual void ConnectROS();

    protected:
        enum MapMode { TRINARY, SCALE, RAW };

        // Info got from the YAML file
        double origin_[3];
        int negate_;
        double occ_th_;
        double free_th_;
        double res_;
        MapMode mode_ = TRINARY;
        std::string frame_id_ = "map";
        std::string map_name_;

        // In order to do ROS2 stuff like creating a service we need a node:
        rclcpp::Node::SharedPtr node_;

        // A service to provide the occupancy grid map and the message with response:
        rclcpp::Service<nav_msgs::srv::GetMap>::SharedPtr occ_service_;
        nav_msgs::msg::OccupancyGrid map_msg_;

        // Publish map periodically for the ROS1 via bridge:
        rclcpp::TimerBase::SharedPtr timer_;
    };

So what is the purpose of the MapFactory class?

To be more specific - what is the advantage of creating a class which holds a pointer of type Abstract class BaseMapServer which is a constructor (I believe) and this weird constructor creates a memory for the new object called OccGridServer and returns it? I got so confused by only writing this. I really want to become a better C++ coder and I am desperate to know the secret behind these code designs.

Aucun commentaire:

Enregistrer un commentaire