c++factory-method

How to get factory method to return a derived class?


I am trying to make a factory method, but it is currently throwing an error:

core\loaders\loader.cpp:11:12: error: cannot convert 'Jpeg' to 'Loader*' in assignment
   15 |     loader = Jpeg(path);
      |              ^~~~~~~~~~
      |              |
      |              Jpeg

I would like to return a class that is derived from Loader, in this case that would be Jpeg. As seen in the code below it does extend the Loader class, and what I have read is that you can use a pointer to the base class, set it, then return it, so I have tried doing that without success. How can I get my factory to return Jpeg (and eventually a Png class).

Here is my Loader header and source:

// loader.h
class Loader {
public:
  static Loader* get(char* path);
};

// loader.cpp
Loader* Loader::get(char* path) {
  string pathStr(path);
  pathStr = pathStr.substr(pathStr.rfind(".") + 1);

  Loader* loader;
  if (pathStr == "jpeg" || pathStr == "jpg") {
    loader = Jpeg(path);
  }

  return loader;
}

The Jpeg class then extends the Loader class:

class Jpeg : public Loader {
protected:
  char* path;

public:

  Jpeg(char* path) {
    this->path = path;
  }
};

Solution

  • The error is self explanatory - type of loader is Loader * which is pointer to Loader type. You can only assign an address to a pointer. Jpeg(path) will create an object of type class Jpeg and not a pointer of type class Jpeg. Looking at your use case, you need to allocate object of type Jpeg dynamically:

    loader = new Jpeg(path);
    

    Once you are done with the Jpeg object, make sure to dealloate the memory using delete operator.


    C++ discourages the use of bare pointers, instead, you should prefer to use the smart pointers. A smart pointer is an abstract data type that simulates a pointer while providing added features, such as automatic memory management. In your code, you can use them like this -

      std::shared_ptr<Loader> loader;
      if (pathStr == "jpeg" || pathStr == "jpg") {
          loader = std::make_shared<Jpeg>(path);
      }
    

    You need to change the return type of Loader::get() function as well -

      std::shared_ptr<Loader> Loader::get(char* path) {
      ^^^^^^^^^^^^^^^^^^^^^^^
    

    and need to do changes in function declaration as well in the similar way.

    Also, when coding in C++, avoid using the char * type and prefer to use string type. For e.g. -

        std::string s{"test.jpeg"};
        std::shared_ptr<Loader> x = Loader::get(s);
    

    In Loader::get(), change the parameter type to std::string & (std::string reference) :

    std::shared_ptr<Loader> Loader::get(std::string & path) {
                                        ^^^^^^^^^^^^^
    

    Need to do changes in class Jpeg also:

    class Jpeg : public Loader {
    protected:
        std::string path;
    
    public:
    
        Jpeg(std::string & path) {
            this->path = path;
        }
    };