Unrelated (Duck-Typed)

Overview

  • Alternative to common base class …

  • … which is too much writing

  • ⟶ Good ol’ C union

  • (Pointer-only though)

  • Manual virtual dispatch (see code/unrelated/virtual.h): switch based on type field.

Sensor Definitions

#pragma once

class Sensor1
{
public:
    Sensor1(double temperature)
    : _temperature{temperature} {}
    double get_temperature() { return _temperature; }
private:
    double _temperature;
};

class Sensor2
{
public:
    Sensor2(double temperature)
    : _temperature{temperature} {}
    double get_temperature() { return _temperature; }
private:
    double _temperature;
};

struct SensorPtr
{
    enum Type
    {
        SENSOR1,
        SENSOR2,
    };
    union variant
    {
        Sensor1* s1;
        Sensor2* s2;
    };
    SensorPtr(Sensor1* s) { type = SENSOR1; variant.s1 = s; }
    SensorPtr(Sensor2* s) { type = SENSOR2; variant.s2 = s; }
    Type type;
    variant variant;
};

Virtual Access

#pragma once

#include "sensors.h"

static inline double get_temperature(SensorPtr s)
{
    switch (s.type) {
        case SensorPtr::SENSOR1: {
            Sensor1* s1 = s.variant.s1;
            return s1->get_temperature();
        }
        case SensorPtr::SENSOR2: {
            Sensor2* s2 = s.variant.s2;
            return s2->get_temperature();
        }
    }
    return -273.15; // <--- never reached
}

Average Across Many

#pragma once

#include "virtual.h"

double average(auto& sensors)  // <--- abbreviated function template
{
    double sum = 0;
    unsigned long num = 0;
    for (auto& s: sensors) {
        ++num;
        sum += get_temperature(s);
    }
    return sum/num;
}

Main Program

#include "sensors.h"
#include "avg.h"
#include <iostream>

int main()
{
    Sensor1 s1{37.1};
    Sensor2 s2{42.666};

    SensorPtr sensors[] = {&s1, &s2};
    
    std::cout << average(sensors) << std::endl;
    return 0;
}