Here's the duck-typing design pattern they introduce in the video (in C++ again, sorry):

#include <conio.h>
#include <memory>
#include <type_traits>
#include <utility>
#include <vector>

class SomeShape
{
public:
    SomeShape() = default;
    explicit SomeShape(int volume) {}

    void draw() const
    {
        _cprintf("Drawing SomeShape\n");
    }
};

class OtherShape
{
public:
    OtherShape() = default;
    explicit OtherShape(int x, int y) {}

    void draw() const
    {
        _cprintf("Drawing OtherShape\n");
    }
};

class ShapeInterface
{
public:
    virtual void draw() const = 0;

    virtual ~ShapeInterface() {}
};

template <typename T>
class PolymorphicShape : public ShapeInterface
{
public:
    template <typename ...Args>
    PolymorphicShape(Args&&... args)
        : _shape (std::forward<Args>(args)...)
    {}

    void draw() const override
    {
        _shape.draw();
    }

private:
    T _shape;
};

template <typename T, typename _ = void>
struct is_shape
    : std::false_type
{};

template <typename T>
struct is_shape<T, typename std::enable_if<
    std::is_same<decltype(T().draw()), void>::value
::type>
    : std::true_type
{};

template <typename T>
auto drawAgain(const T& shape) -> typename std::enable_if<
    is_shape<T>::value
::type
{
    shape.draw();
}

int main()
{
    std::vector<std::unique_ptr<ShapeInterface>> shapes;

    shapes.emplace_back(new PolymorphicShape<SomeShape>(42));
    shapes.emplace_back(new PolymorphicShape<OtherShape>(1, 2));

    // Dynamic polymorphism:
    shapes[0]->draw(); // Prints: Drawing SomeShape
    shapes[1]->draw(); // Prints: Drawing OtherShape

    // Static polymorphism:
    drawAgain(SomeShape(123));   // Prints: Drawing SomeShape
    drawAgain(OtherShape(2, 4)); // Prints: Drawing OtherShape

    _getch();
    return 0;
}


Reply via email to