Classic Virtual

Overview

  • Classic polymorpism: common base class - interface

  • Virtual dispatch per language support (this is what virtual is there for)

  • Type erasure: not seeing derived types (a.k.a. concrete types) across the program - only the interface

  • Easy to use: call base class pointer ⟶ dynamic dispatch

  • Pro: easy polymorphic use (e.g. store object of different derived type in an array of pointer-to-base-type)

  • Con: code bloat, measured in binary size

Sensor Definitions

#pragma once

class Sensor
{
public:
    virtual ~Sensor() = default;
    virtual double get_temperature() = 0;
};

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

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

Virtual Access

This is easy - just call virtual method …

#pragma once

static inline double get_temperature(Sensor* s)
{
    return s->get_temperature();
}

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};

    Sensor* sensors[] = {&s1, &s2};

    std::cout << average(sensors) << std::endl;
    return 0;
}