Is there a way to have a member parameter type be a pointer to a derived class

Viewed 62

I'm writing a module system for my program, where individual modules are initialised and shutdown by a system.

how this works is I call an Init() function that will initialise a static pointer of the class.

this works and is fine, however: I would like to abstract this into a class so the api is easier to maintain, but I don't know how to change the pointer type of the derived class automatically

for example, if I have the base class IModule:

class IModule {
public:
protected:
   result Init();
   result Shutdown();

private:
   static IModule* s_instance;
};

is there a way I can write this class so that the derived class can be written as

class Derived : public IModule {
protected:
   result Init();
   result Shutdown();
}

and have Derived::s_instance evaluate to a Derived*

2 Answers

No, you can't have a variable whose type depends on the type of this. However, you can have a variable whose type depends on a template parameter.

template <typename T>
class IModule {
private:
  static T* s_instance;
};

class Derived : public IModule<Derived> {
  // The s_instance in this class is of type Derived*.
}

This is called the curiously recurring template pattern and it's used to do all sorts of tricks in C++. It may not work for your use case (for instance, you can no longer have a list of IModule which all have different derived types), but depending on what exactly you're doing this may be the way to go.

You can do this as long as the return types are covariant, i.e., Derived::Init() returns something derived from Derived::IModule()'s return type. Which is I think the case here. A simplified version:

#include <iostream>

struct IModule {
   virtual IModule* Init() = 0;
   
private:
   static IModule* s_instance;
};

class Derived : public IModule {
    Derived* Init() override { std::cout << "1" << std::endl; return this; }
};

int main() {
    IModule* ptr = new Derived();
    ptr->Init(); // compile-time type: IModule, runtime: Derived
}
Related