pthom / function_list_vs_abtsract_interface

explores a possible alternative to pure abstract interfaces in C++, under the form of a list of std::function

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Functions list versus abstract interface

This proof of concept explores a possible alternative to pure abstract interfaces, under the form of a simple struct that will contain any number of std::function.

For example, an interface like

class ICamera {
public:
  virtual cv::Mat grab() = 0;
};

can be replaced by

struct CameraFunctions: AnyFunctionList {
  std::function<cv::Mat(void)> grab;
};

In the application code, instead of storing something like std::unique_ptr<ICamera> (which will in effect be a derivate that contains the actual state), a struct StatefulFunctionList<CameraFunctions> will be stored. This is a template class which contains the interface and the state of the implementation, but the states remains totally hidden it from the application code.

Full example:

This example explores a possible use, where we need an interface and a factory that depends on the application settings (strategy pattern).

Implementation with an abstract interface

// Interface as an abstract class
class ICamera
{
public:
  virtual ~ICamera() = default;
  virtual cv::Mat grab() = 0;
  virtual double get_contrast() = 0;
  virtual void set_contrast(double v) = 0;
};


// Concrete implementation as a derivate
class CameraMock: public ICamera
{
public:
  ~CameraMock() = default;
  cv::Mat grab() override {
    return MakeImageWithCounter(++frameCounter_);
  }
  double get_contrast() override { return contrast_; };
  void set_contrast(double v) override { contrast_ = v; }
private:
  int frameCounter_ = 0; // The state is mixed with the concrete implementation
  double contrast_ = 0.5;
};


// Factory
std::unique_ptr<ICamera> FactorCamera(const AppSettings & appSettings)
{
  if (appSettings.useCameraMock)
    return std::make_unique<CameraMock>();
  throw std::logic_error("Not finished");
}

Implementation with a function list

See stateful_functions.h for the implementation of StatefulFunctionList.

// Interface as a function list
struct CameraFunctions
{
  std::function<cv::Mat(void)> grab;
  std::function<double(void)> get_contrast;
  std::function<void(double)> set_contrast;
};


// Concrete implementation with a separate state
struct CameraMockState: AnyState {
  int frameCounter = 0;
  double contrast = 0.5;
};

StatefulFunctionList<CameraFunctions> FactorCameraMock()
{
  // The state is forcefuly hidden from the function list
  auto state = std::make_shared<CameraMockState>();
  StatefulFunctionList<CameraFunctions> r(state);

  // In the implementation, `state->` acts as a synonym of `this->'
  // if we were using an abstract class
  r->grab = [state]() {
      return MakeImageWithCounter(++ state->frameCounter);
  };
  r->get_contrast = [state]() { return state->contrast; };
  r->set_contrast = [state](double v) { state->contrast = v; };
  return r;
};


// Factory
StatefulFunctionList<CameraFunctions> FactorCamera(const AppSettings & appSettings)
{
  if (appSettings.useCameraMock)
    return FactorCameraMock();
  throw std::logic_error("Not finished");
}

Build instructions

prerequisites : conan & opencv

You need to install the conan package manager (see instructions at http://conan.io)

Opencv is a dependency that is installed via conan.

You will then need to add a conan remote for opencv

conan remote add camposs "https://conan.campar.in.tum.de/api/conan/conan-camposs"

How to build

mkdir build
cd build
conan install .. --build=missing  # will download / build opencv 
cmake ..
make

How to run

Launch ./abstract_class_interface or ./function_list_interface

About

explores a possible alternative to pure abstract interfaces in C++, under the form of a list of std::function


Languages

Language:C++ 87.6%Language:CMake 7.3%Language:C 5.1%