-2

I would like to use a generic interface that has been implemented.

I have two classes as such:

class App {
  MainWindow<State> mainWindow;

  protected:
    virtual MainWindow<State> provideMainWindow() = 0;

  public:
    void exec(){
      // Do something with MainWindow<State>
    }

};

template<class StateType>
class MainWindow {
  protected:
    virtual StateType provideState() = 0;
};

Then, I implement the classes as such:

class ExampleMainWindow : public MainWindow<ExampleMainWindowState> {
  protected:
    ExampleMainWindowState provideState() override{
      return ExampleMainWindowState();
    }
};

class ExampleApp : public App {
  protected:
    MainWindow<State> provideMainWindow() override {
      // Here is where I'm noticing the difficulty in using the abstract class
      return static_cast<MainWindow<State>>(ExampleMainWindow());
    }

}

The compiler tells me that it cannot allocate an abstract class. I tried using pointers, but I couldn't find a way using pointers, either, as new errors began to show up; the compiler wouldn't let me try redefining everything to use pointers such that I could use dynamic_cast<MainWindow<State*>*>(new ExampleMainWindow()), either, even though that would be a bit messy.

4

C++ is a value-oriented language, in the sense that variables and return values work by-value, not by-reference as in more dynamic languages such as Java or TypeScript. A variable of type A cannot hold a value of type B even if there's an inheritance relationship class B: public A. After all, a B value might contain additional data that does not fit into a memory location that was sized to hold A values. C++ will silently forget about the extra parts (“object slicing”) which will lead to unexpected behaviour.

To make size irrelevant, you must use some kind of pointer. Raw pointers are difficult to use correctly, so let's try a smart pointer like std::unique_ptr<T> instead.

This code does not work as expected because MainWindow and ExampleMainWindow are different types:

MainWindow<State> provideMainWindow() {
    return ExampleMainWindow();
}

Instead, returning a pointer type lets us safely return subclasses of the return type:

std::unique_ptr<MainWindow<State>> provideMainWindow() {
    return std::make_unique<ExampleMainWindow>();
}

You have further complicated matters by using templates. Templates and inheritance can combine in unexpected ways in C++. Templates are not generics, each template instantiation with distinct parameters leads to a distinct type. There is no relationship between Template<A> and Template<B>.

Fortunately, that will not be a large issue for your scenario. Instead, note that you are referring to a type State within App without declaring such a type. You likely want a template<class State> class App. Whenever you use App later, you will have to supply the appropriate template argument (e.g. ExampleMainWindowState). If such template parameters permeate your design, this can get in the way. Sometimes, the compile-time safety of template parameters can be sacrificed, and similar behaviour modelled with inheritance and run-time checks. But without knowing the context and forces on your design, it's impossible to tell whether that could be advantageous here.

Not the answer you're looking for? Browse other questions tagged or ask your own question.