简体   繁体   中英

Using templates for polymorphism

So I've got some compile time polymorphism in some legacy code. ie

I have a base class to use that takes in a template parameter.

template<typename HANDLER>
class Base
{
  virtual HANDLER * make_handler();
  // other methods
};

make_handler constructs the HANDLER using a specific constructor that takes in two arguments (important later).

The handler is generally the only thing we need to change for code sharing that does a single method std::size_t handle_data(const char *, std::size_t length); which is the entry point

class SpecificHandler
{
  SpecificHandler(uint32_t id, uint32_t source_id);
  std::size_t handle_data(const char *, std::size_t length);
  // other methods
};

That we use by

class Child : public Base<SpecificHandler>
{
  // other overridden methods
};

The problem I have is that I would like to pass in another parameter in my SpecificHandler class ie

class OtherSpecificHandler
{
  OtherSpecificHandler(uint32_t id, uint32_t source_id, uint32_t other_id);
};

unfortunately the Base class calls the two argument constructor in the template.

The work around I have at the moment is to override the make_handler() call to return the handler created with the 3 argument constructor ie

class Child : public Base<OtherSpecificHandler>
{
  virtual OtherSpecificHandler * make_handler();
  // other overridden methods
};

Unfortunately because the template stuff is done at compile time I have to still provide the 2 argument constructor, (in fact I just provided a default argument for the third argument), which feels wrong.

Normally I would solve this problem using dependency injection with a pointer for the Handler rather than using templates, but this is used in a lot of places and I would rather not change it.

What are my other options?

Thanks

First thing that comes to mind is making the base class method pure virtual:

template<typename HANDLER>
class Base
{
  virtual HANDLER * make_handler() = 0;
  //other stuff
};

That would of course mean that every derived class has to overload make_handler , even if every other handler class has the same two-argument constructor. To avoid the repetition in that, insert another layer into the hierarchy:

template<typename HANDLER>
class BaseWithStandardHandlerConstruction : public Base<Handler>
{
  virtual HANDLER * make_handler() override //maybe final as well?
  {
    return new HANDLER("meow", 4);
  }
  //that's it - nothing else goes here...
};

Then any class with a "normal" handler derives from the latter, while classes with "special" handlers derive from the former:

class Child : public BaseWithStandardHandlerConstruction<SpecificHandler>
{
  // other overridden methods, no make_handler needed
};

class OtherChild : public Base<OtherSpecificHandler>
{
  virtual OtherSpecificHandler * make_handler() override;
  // other overridden methods
};

You may template specialize Base

Something like

template <>
OtherSpecificHandler* Base<OtherSpecificHandler>::make_handler() {
    return new OtherSpecificHandler(42, 5, 12); // With correct parameter ofc.
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM