#include <iostream>
#include <cstdint>

#define  w(expr)  std::cout << #expr << ": " << expr << std::endl

class B {
public:
    uint64_t sum() const { return b; }

// protected:
private:
    uint64_t b = 100;
};

class D : public B {
public:
    // uint64_t sum() const { return b + d; }
    uint64_t sum() const { return B::sum() + d; }

private:
    uint64_t d = 200;
};

int main() {
    using namespace std;

    // 1. Inheritance basics

    D x;
    w( x.sum() );

    /*
    // 2. Memory layout of derived classes

    cout << "*** Object layout" << endl;
    w( sizeof(x) );
    uint64_t* p = (uint64_t*)&x;
    // uint64_t* p = reinterpret_cast<uint64_t*>(&x);
    w( p[0] );
    w( p[1] );

    // Use the following when we make sum() virtual:
    // w( reinterpret_cast<void*>(p[0]) );
    // w( p[1] );
    // w( p[2] );

    // 3. Static vs. dynamic binding

    cout << "*** Pointer/reference to B can bind to a D object" << endl;
    B* pb = &x;
    D* pd = &x;
    w( pb );
    w( pd );
    w( pb->sum() );
    w( pd->sum() );

    // 4. Virtual function table (vtable)

    cout << "*** Calling a virtual function manually" << endl;
    cout << ((uint64_t (***)(const D*))pb)[0][0](&x) << endl;
    */
}
