-2

I have some class hierarchy implemented in C :

typedef struct analog_sensor analog_sens;

struct analog_sensor{
        .... /*some  fields*/ 

        void (*fill_output_buf)(analog_sens *, int *);
        
        ..... /*some other fields*/
};

typedef struct {
    analog_sens sensor;
    void (*fill_output_buf)(analog_sens *, int *);
    .../* some other fields */
}ecg_analog_sens ;

I have two analog sensors, ecg sensor and acoustic. They both fill the output buffer by calling following logic which is the same for both sensors:

void fill_output_buffer(analog_sens *sensor,
        int *output_length)
{
    ... /* some logic copying filters output to output buffer */
    .... 
    .....
    
}

And then somewhere during the initialization I do the following assignments:

    ecg_sens.fill_output_buf = &fill_output_buffer;
    acoustic_sens.fill_output_buf = &fill_output_buffer;

Now ecg sensor has some more data to put to the output buffer, and I need to extend (override) the base fill_output_buffer function with some more logic. So in initialization phase of ecg instance I do the following:


void ads1299_hog_init(analog_sens *ecg_sens)
{

    /* fill_output_buf function override
    * This is the part I don't like, as I 
    * have to keep pointer to base function
    * on inherited object. It will look 
    * very confusing for someone who will 
    * have to maintain the code in the future
    */ 
    ((ecg_analog_sens* )ecg_sens)->fill_output_buf = ecg_sens->fill_output_buf;
    ecg_sens->fill_output_buf = ads1299_fill_output_buf;
    /* fill_output_buf function override end*/
}

void ads1299_fill_output_buf(analog_sens *sens, int *output_length)
{
    ecg_analog_sens *sensor = (ecg_analog_sens*) sens;
    /* call parrent fill_output_buf */
    /*
    * This is the part I don't like, as I 
    * have to call the base function from 
    * an instance of inherited object. 
    * This might be very confusing for someone 
    * who will have to maintain the code 
    */
    sensor->fill_output_buf(sens, output_length);

    ..../*some additional logic extending the base function */

}


So when I invoke sensor->fill_output_buf(sensor, &output_length); on ecg_sens instance I'm actually calling the ads1299_fill_output_buf function. As I write in the comments above I don't like the fact that the base function is called from an inherited object. This is too confusing. So I'm looking for some other idea or a known solution. Probably some new keyword that might solve this better. There is this new _Generic keyword, for example, in C11 with effect of function overload How to achieve function overloading in C? but I can't see how it can help in my situation.

Thanks.

Dabo
  • 2,371
  • 2
  • 18
  • 26
  • what is the purpose of adding an extra `fill_output_buf` in `ecg_analog_sens`. Why not use `sensor.fill_output_buf` ? – tstanisl Aug 20 '21 at 20:14
  • @tstanisl Because I need to keep somewhere the pointer to the base function, as I only want to use it as is with some extension, not to totally override it. Actually that is what I'm looking for, to rid off this overcomplication – Dabo Aug 20 '21 at 20:22
  • it looks a bit odd. Are you sure that `analog_sensor::fill_output_buf` should be polymorphic? Maybe add a normal function `analog_sensor_fill_output_buf(analog_sens*,int*)` that does `analog_sensor` stuff and additionally calls `fill_output_buf` internally letting derived classes tweak the original `analog_sensor_fill_output_buf()`? – tstanisl Aug 20 '21 at 20:37
  • @tstanisl I do have a mistake in my understanding how overriding in C++ works, I see it now. I will add an update to the question – Dabo Aug 21 '21 at 06:34

1 Answers1

2

As I understand, you need to call the original fill_output_buffer bypassing a virtual call via sensor.fill_output_buf pointer. Why not get rid of fill_output_buf from the ecg_analog_sens and call fill_output_buffer directly from ads1299_fill_output_buf().

typedef struct {
    analog_sens sensor;
    .../* some other fields */
}ecg_analog_sens ;

void ads1299_hog_init(analog_sens *ecg_sens)
{
    ecg_sens->fill_output_buf = ads1299_fill_output_buf;
}

void ads1299_fill_output_buf(analog_sens *sens, int *output_length)
{
    ecg_analog_sens *sensor = (ecg_analog_sens*) sens;
    fill_output_buffer(sens, output_length);
    ..../*some additional logic extending the base function */
}
tstanisl
  • 13,520
  • 2
  • 25
  • 40
  • +1 but I don't want direct dependency from inherited class. Calling `fill_output_buffer` like that will make me either to include header with `fill_output_buffer` prototype inside the `ads1299.c` file or make `extern ...` declaration of `fill_output_buffer`. – Dabo Aug 21 '21 at 06:28
  • @Dabo, your question looks very similar to https://stackoverflow.com/q/10177809/4989451 . The most upvoted answer is similar to mine. The cleanest way is to make fill_output_buffer visible for ads1299 – tstanisl Aug 22 '21 at 16:02
  • It is cleanest in C++ : `Base::fun();` in C it breaks the OOD, which I don't want. I solved it with extension, from the base function I call `sens->fill_output_buf_extension()` and I implement additional logic inside it... – Dabo Aug 23 '21 at 07:46