I'm currently working with a system/data hierarchy designed as you can see below. Systems represent bare interfaces to some sort of hardware component which is able to deliver raw data to then be further processed into some final representation.

Code:
class SystemData
{
}

class SystemDataA : public SystemData
{
  int x;
}

class SystemDataB : public SystemData
{
  float y;
}

class System
{
  virtual SystemData* getData() = 0;
  virtual Result computeData(SystemData*) = 0;
}

class SystemA : public System
{
  // really returns SystemDataA
  SystemData* getData() override;
  Result computeData(SystemData*) override;
}

class SystemB : public System
{
  // really returns SystemDataB
  SystemData* getData() override;
  Result computeData(SystemData*) override;
}

void Controller::finalProcessing()
{
  for(auto& s : systemVec)
  {
    SystemData* data = s->getData();
    FinalResult final = s->computeData(data);
  }
}
The problem here is: Each system returns a concrete data type abstracted away in some common interface, which is a nice idea. To further process it, there is however still some sort of runtime information needed from which system the data came from because the further processing steps depend on this. To get to this piece of information, the author apparently just passed it back into the system where imo it doesn't belong at all, dynamic_casts to the concrete type in the first line of each compute-function and does the processing there. To me this looks like circumventing all the nice purposes of abstract inheritance hierarchies whilst making it overly complicated.

So what I'm thinking of to make this better is some sort of encapsulated processing algorithm hierarchy. Since they don't carry any state and are really just single methods, maybe a map of function pointers will already do. Each data type then has to carry a piece of information (either just an enum type or a function pointer) of which algorithm to use but can in the end be done completely isolated from the system.
The problem remains however that I must dynamic_cast or identify the concrete data type to feed it into the correct algorithm. So this still doesn't look like the cleanest design there is. Any ideas on how to make this better?