How to get factory method to return a derived class?

82 Views Asked by At

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;
  }
};
1

There are 1 best solutions below

1
H.S. On BEST ANSWER

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;
    }
};