class Polymorphic1 {
    virtual void f() {}
}
class Polymorphic2 : public Polymorphic1 {
}
class Polymorphic3 {
    virtual void f() final {}
}
class Polymorphic4 {
    virtual void f() = 0;
}class Base {
public:
   virtual ~Base();
};
class Derived : public Base {
}Base* p = new Derived;
// static type Base
// dynamic type Deriveddynamic_cast
Base* b = new Derived1();
auto s_d1 = static_cast<Derived1*>(b);
auto s_d2 = static_cast<Derived2*>(b); // UB
auto d_d1 = dynamic_cast<Derived1*>(b);
auto d_d2 = dynamic_cast<Derived2*>(b); // nullptrBase* b = new Derived1();
Base& b_ref = *b;
auto s_d1 = static_cast<Derived1&>(b_ref);
auto s_d2 = static_cast<Derived2&>(b_ref); // UB
auto d_d1 = dynamic_cast<Derived1&>(b_ref);
auto d_d2 = dynamic_cast<Derived2&>(b_ref); // throw std::bad_castclass TuringMachine {
private:
    InfiniteArray<state> _tape;
    state _current_state;
public:
    TuringMachine() :
        _tape{ state::empty },
        _current_state{ state::start_state }
    {
    }
    struct transition_result {
        state new_state;
        state new_symbol;
        enum {
            Left, Right, None
        } tape_movement;
    };
    
    virtual transition_result transition(const state& current_state, const state& symbol) = 0;
};class Computer : public TuringMachine { ... };class TuringMachine {
    ...
};
class ElectronicDevice {
    ...
};class Computer : public TuringMachine, public ElectronicDevice {
    ...
};class Derived : public Base1, public Base2, public BaseN {
    ...
};struct Base1 {
    void b1();
};
struct Base2 {
    int b2 = 3;
};
struct Derived : Base1, Base2 {
};
void foo() {
    Derived d;
    d.b1();
    d.b2 = 3;
}struct Base1 {
    void b1();
};
struct Base2 {
protected:
    int b2 = 3;
};
struct Derived : Base1, Base2 {
    using Base2::b2;
};
void foo() {
    Derived d;
    d.b1();
    d.b2 = 3;
}struct Base1 {
    void print(int) {
        std::cout << "i\n";
    }
};
struct Base2 {
    void print(float) {
        std::cout << "f\n";
    }
};
struct Derived : Base1, Base2 {
};
void foo() {
    Derived d;
    d.print(3);    // ambiguous
    d.print(2.0f); // ambiguous
}d.print()
Derived
Base1
Base2
Derived::print
Base1::print
Base2::print
Name lookup
struct Base1 {
    void print(int) {
        std::cout << "i\n";
    }
};
struct Base2 {
    void print(float) {
        std::cout << "f\n";
    }
};
struct Derived : Base1, Base2 {
};
void foo() {
    Derived d;
    d.print(3);    // ambiguous
    d.print(2.0f); // ambiguous
}d.print()
Derived
Base1
Base2
Derived::print
Base1::print
Base2::print
Name lookup
struct Base1 {
    void print(int) {
        std::cout << "i\n";
    }
};
struct Base2 {
    void print(float) {
        std::cout << "f\n";
    }
};
struct Derived : Base1, Base2 {
};
void foo() {
    Derived d;
    d.print(3);    // ambiguous
    d.print(2.0f); // ambiguous
}d.print()
Derived
Base1
Base2
Derived::print
Base1::print
Base2::print
Name lookup
struct Base1 {
    void print(int) {
        std::cout << "i\n";
    }
};
struct Base2 {
    void print(float) {
        std::cout << "f\n";
    }
};
struct Derived : Base1, Base2 {
};
void foo() {
    Derived d;
    d.print(3);    // ambiguous
    d.print(2.0f); // ambiguous
}d.print()
Derived
Base1
Base2
Derived::print
Base1::print
Base2::print
Name lookup
struct Base1 {
    void print(int) {
        std::cout << "i\n";
    }
};
struct Base2 {
    void print(float) {
        std::cout << "f\n";
    }
};
struct Derived : Base1, Base2 {
};
void foo() {
    Derived d;
    d.print(3);    // ambiguous
    d.print(2.0f); // ambiguous
}d.print()
Derived
Base1
Base2
Derived::print
Base1::print
Base2::print
Name lookup
struct Base1 {
    void print(int) {
        std::cout << "i\n";
    }
};
struct Base2 {
    void print(float) {
        std::cout << "f\n";
    }
};
struct Derived : Base1, Base2 {
};
void foo() {
    Derived d;
    d.print(3);    // ambiguous
    d.print(2.0f); // ambiguous
}d.print()
Derived
Base1
Base2
Derived::print
Base1::print
Base2::print
Name lookup
struct Base1 {
    void print(int) {
        std::cout << "i\n";
    }
};
struct Base2 {
    void print(float) {
        std::cout << "f\n";
    }
};
struct Derived : Base1, Base2 {
};
void foo() {
    Derived d;
    d.print(3);    // ambiguous
    d.print(2.0f); // ambiguous
}d.print()
Derived
Base1
Base2
Derived::print
Base1::print
Base2::print
Name lookup
struct Base1 {
    void print(int) {
        std::cout << "i\n";
    }
};
struct Base2 {
    void print(float) {
        std::cout << "f\n";
    }
};
struct Derived : Base1, Base2 {
};
void foo() {
    Derived d;
    d.print(3);    // ambiguous
    d.print(2.0f); // ambiguous
}d.print()
Derived
Base1
Base2
Derived::print
Base1::print
Base2::print
Name lookup
ambiguous
struct Base1 {
    void print(int) {
        std::cout << "i\n";
    }
};
struct Base2 {
    void print(float) {
        std::cout << "f\n";
    }
};
struct Derived : Base1, Base2 {
};
void foo() {
    Derived d;
    d.Base1::print(3);    // i
    d.Base2::print(2.0f); // f
}d.print()
Derived
Base1
Base2
Derived::print
Base1::print
Base2::print
Name lookup
struct Base1 {
    void print(int) {
        std::cout << "i\n";
    }
};
struct Base2 {
    void print(float) {
        std::cout << "f\n";
    }
};
struct Derived : Base1, Base2 {
    using Base1::print;
};
void foo() {
    Derived d;
    d.print(3);    // i
    d.print(2.0f); // i
}d.print()
Derived
Base1
Base2
Base1::print
Base1::print
Base2::print
Name lookup
struct Base1 {
    void print(int) {
        std::cout << "i\n";
    }
};
struct Base2 {
    void print(float) {
        std::cout << "f\n";
    }
};
struct Derived : Base1, Base2 {
    using Base1::print;
    using Base2::print;
};
void foo() {
    Derived d;
    d.print(3);    // i
    d.print(2.0f); // f
}d.print()
Derived
Base1
Base2
Base1::print Base2::print
Base1::print
Base2::print
Name lookup
struct Base1 {
    void print(int) {
        std::cout << "i\n";
    }
};
struct Base2 {
    void print(float) {
        std::cout << "f\n";
    }
};
struct Derived : Base1, Base2 {
    using Base1::print;
    using Base2::print;
};
void foo() {
    Derived d;
    d.print(3);    // i
    d.print(2.0f); // f
}print(float) print(int)
overload set
Overload resolution
d.print(3) d.print(2.0f)
print(int) print(float)
struct Adder {
    float toAdd;
    Adder(float val) : toAdd{val} {}
    int operator()(float x) const { 
        return x + toAdd;
    }
};
struct Fib {
    std::vector<int> sequence;
    Fib(size_t count) :
    	sequence{ create_seq(count) }
    {
    }
private:
    ...
};struct Derived : Adder, Fib {};
void foo() {
    Derived d; // error: no default ctor
    Derived d{3.0f, 2}; // ok: implicit conversion
}struct Adder {
    float toAdd;
    explicit Adder(float val) : toAdd{val} {}
    int operator()(float x) const { 
        return x + toAdd;
    }
};
struct Fib {
    std::vector<int> sequence;
    explicit Fib(size_t count) :
    	sequence{ create_seq(count) }
    {
    }
private:
    ...
};struct Derived : Adder, Fib {};
void foo() {
    Derived d; // error: no default ctor
    Derived d{3.0f, 2}; // error: no conversion
    Derived d{Adder{3.0f}, Fib{2}} // ok
}struct Adder {
    float toAdd;
    explicit Adder(float val) : toAdd{val} {}
    int operator()(float x) const { 
        return x + toAdd;
    }
};
struct Fib {
    std::vector<int> sequence;
    explicit Fib(size_t count) :
    	sequence{ create_seq(count) }
    {
    }
private:
    ...
};struct Derived : Adder, Fib {
    int x;
    Derived(int toAdd, size_t count) :
    	Adder{toAdd},
        Fib{count},
        x{42} // after base classes
    {
    }
};
void foo() {
    Derived d; // error: no default ctor
    Derived d{3.0f, 2}; //  ok
}struct Adder {
    float toAdd;
    explicit Adder(float val = .0f) : toAdd{val} {}
    int operator()(float x) const { 
        return x + toAdd;
    }
};
struct Fib {
    std::vector<int> sequence;
    explicit Fib(size_t count = 0) :
    	sequence{ create_seq(count) }
    {
    }
private:
    ...
};struct Derived : Adder, Fib {
    using Adder::Adder;
    using Fib::Fib;
};
void foo() {
    Derived d1;
    Derived d2{3.0f};
    Derived d3{size_t(2)};
    Derived d3{2uz}; // since C++23
}class IPrintable {
public:
    virtual void print() const = 0;
};
class IMeowable {
    virtual void moew() const noexcept = 0;
};class MeowingCatPhoto : public Image, public IPrintable, public IMeowable {
public:
    virtual void print() const override {
        Pixel* pixels = getPixels();
        ...
    }
    virtual void moew() const noexcept override {
        ...
    }
}struct Pixel {
    float r, g, b;
};
class Image {
    using data_t = Pixel[768][1024];
    data_t pixels;
public:
    [[nodiscard]] const Pixel* getPixels() const noexcept;
    ...
};struct Base {
    int x, y;
};
struct Derived : Base {
    int z, w;
};x
y
z
w
Derived der;
Base* pBase = &der;
Derived* pDerived = static_cast<Derived*>(pBase);struct Base {
    int x, y;
    virtual void foo() {}
};
struct Derived : Base {
    int z, w;
};x
y
z
w
VFTablePtr
Derived der;
Base* pBase = &der;
Derived* pDerived = static_cast<Derived*>(pBase);x
y
z
w
VFTablePtr
struct Base {
    int x, y;
    virtual void foo() {}
};
struct Derived : Base {
    int z, w;
};
struct Base2 {
    int a, b;
}
struct Derived2 : Derived, Base2 {
    int g;
}Derived2 d2;
Derived* pDerived = &d2;
Base2* pBase2 = &d2;
Base* pBase = &d2;
auto* p_derived = static_cast<Derived2*>(pBase2);
auto* p_derived2 = static_cast<Derived2*>(pDerived);
auto* p_derived3 = static_cast<Derived2*>(pBase);a
b
g
...
...
VFTablePtr
struct Base {
    ...
    virtual void foo() {}
};
struct Derived : Base {
    ...
};
struct Base2 {
    ...
}
struct Derived2 : Derived, Base2 {
    ...
}Derived2 d2;
Derived* pDerived = &d2;
Base2* pBase2 = &d2;
Base* pBase = &d2;
auto* p_derived = static_cast<Derived2*>(pBase2);
auto* p_derived2 = static_cast<Derived2*>(pDerived);
auto* p_derived3 = static_cast<Derived2*>(pBase);...
...
...
...
VFTablePtr
...
...
auto* p_derived = static_cast<Derived2*>(pBase2);
..B7A  cmp    qword ptr [pBase2],0  
..B82  je     main+0A8h (07FF720981B98h)  
..B84  mov    rax,qword ptr [pBase2]  
..B8B  sub    rax,28h  
..B8F  mov    qword ptr [rbp+1D8h],rax  
..B96  jmp    main+0B3h (07FF720981BA3h)  
..B98  mov    qword ptr [rbp+1D8h],0  
..BA3  mov    rax,qword ptr [rbp+1D8h]  
..BAA  mov    qword ptr [p_derived],rax  
auto* p_derived2 = static_cast<Derived2*>(pDerived);
..BB1  mov    rax,qword ptr [pDerived]  
..BB5  mov    qword ptr [p_derived2],rax  struct Base {
    ...
    virtual void foo() {}
};
struct Derived : Base {
    ...
};
struct Base2 {
    ...
}
struct Derived2 : Derived, Base2 {
    ...
}Derived2 d2;
Derived* pDerived = &d2;
Base2* pBase2 = &d2;
Base* pBase = &d2;
auto* p_derived = static_cast<Derived2*>(pBase2);
auto* p_derived2 = static_cast<Derived2*>(pDerived);
auto* p_derived3 = static_cast<Derived2*>(pBase);...
...
VFTablePtr
...
...
struct Base {
    ...
    virtual void foo() {}
};
struct Derived : Base {
    ...
};
struct Base2 {
    ...
    virtual void bar() {}
}
struct Derived2 : Derived, Base2 {
    ...
}VFTablePtr
Derived2 d2;
Derived* pDerived = &d2;
Base* pBase = &d2;
Base2* pBase2 = &d2;
pDerived->foo();
pBase->foo();
pBase2->bar();class Base {
    ...
};
class Derived1 : public Base {
    ...
};
class Derived2 : public Base {
    ...
};
class Derived12 : public Derived1, public Derived2 {
    ...
};class Base { ... };
class Derived1 : public Base { ... };
class Derived2 : public Base { ... };
class Derived12 : public Derived1, public Derived2 { ... };...
...
...
...
...
struct Base {
    void bar() {}
};
struct Derived1 : Base { };
struct Derived2 : Base { };
struct Derived12 : Derived1, Derived2 { };Derived12 d;
d.bar(); // ambiguous
d.Derived1::bar();
d.Derived2::bar();
auto pBase = static_cast<Base*>(&d); // ambiguous
auto pBase1 = static_cast<Base*>(static_cast<Derived1*>(&d));
auto pBase2 = static_cast<Base*>(static_cast<Derived2*>(&d));
auto pD12 = static_cast<Derived12*>(pBase); // ambiguous
auto pD12_1 = static_cast<Derived12*>(static_cast<Derived1*>(pBase);
auto pD12_2 = static_cast<Derived12*>(static_cast<Derived1*>(pBase);
d.bar()
Derived12
Derived1
Derived1
Base
Base
ambiguous
struct Base {
    virtual void bar() = 0;
};
struct Derived1 : Base { };
struct Derived2 : Base { };
struct Derived12 : Derived1, Derived2 { 
	virtual void bar() override {
        std::cout << "d12\n";
    }
};Derived12 d;
auto pDerived1 = static_cast<Derived1*>(&d);
auto pDerived2 = static_cast<Derived2*>(&d);
auto pBase1 = static_cast<Base*>(pDerived1);
auto pBase2 = static_cast<Base*>(pDerived2);
pDerived1->bar(); // ok
pDerived2->bar(); // ok
pBase1->bar(); // ok
pBase2->bar(); // okVFTablePtr
VFTablePtr
struct Base {
    virtual void bar() = 0;
};
struct Derived1 : Base { };
struct Derived2 : Base { };
struct Derived12 : Derived1, Derived2 { 
	virtual void bar() override {
        std::cout << "d12\n";
    }
};Derived12 d;
auto pDerived1 = static_cast<Derived1*>(&d);
auto pDerived2 = static_cast<Derived2*>(&d);
auto pBase1 = static_cast<Base*>(pDerived1);
auto pBase2 = static_cast<Base*>(pDerived2);
pDerived1->bar(); // ok
pDerived2->bar(); // ok
pBase1->bar(); // ok
pBase2->bar(); // okVFTablePtr
VFTablePtr
Still two Base instances
struct Base {
    virtual void bar() = 0;
};
struct Derived1 : virtual Base { }; // instrusive
struct Derived2 : virtual Base { }; // instrusive
struct Derived12 : Derived1, Derived2 { 
	virtual void bar() override {
        std::cout << "d12\n";
    }
};VFTablePtr
VBasePtr
VBasePtr
Derived12 d12;
Derived1* pd1 = &d12;
Derived2* pd2 = &d12;
Base* pb = &d12;struct Base {
    virtual void bar() = 0;
};
struct Derived1 : virtual Base { }; // instrusive
struct Derived2 : virtual Base { }; // instrusive
struct Derived12 : Derived1, Derived2 { 
	virtual void bar() override {
        std::cout << "d12\n";
    }
};VFTablePtr
VBasePtr
VBasePtr
Derived12 d12;
Derived1* pd1 = &d12;
Derived2* pd2 = &d12;
Base* pb = &d12;auto pd12_1 = static_cast<Derived12*>(pd1); // ok
auto pd12_2 = static_cast<Derived12*>(pd1); // ok
auto pd12_3 = static_cast<Derived12*>(pb); // no, why??..struct Base {
    virtual void bar() = 0;
};
struct Derived1 : virtual Base { }; // instrusive
struct Derived2 : virtual Base { }; // instrusive
struct Derived12 : Derived1, Derived2 { 
	virtual void bar() override {
        std::cout << "d12\n";
    }
};VFTablePtr
VBasePtr
VBasePtr
Derived12 d12;
Derived1* pd1 = &d12;
Derived2* pd2 = &d12;
Base* pb = &d12;auto pd12_1 = static_cast<Derived12*>(pd1); // ok
auto pd12_2 = static_cast<Derived12*>(pd1); // ok
auto pd12_3 = dynamic_cast<Derived12*>(pb); // okstruct B {
    B() = delete;
    B(int);
};
struct D1 : virtual B {
    D1(int x) : B(x) {}
};
struct D2 : virtual B {
    D2(int x) : B(x) {}
};struct D12 : D1, D2 {
    D12(int x) : B(x), D1(x), D2(x) {}
};struct D12 : D1, D2 {
    D12(int x) : D1(x), D2(x) {}
};struct D : virtual B, D1, D2 {
    D(int x) : B(x), D1(x) {}
};struct B {
    B() = default;
    B(int);
};
struct D1 : virtual B {
    D1(int x) : B(x) {}
};
struct D2 : virtual B {
    D2(int x) : B(x) {}
};struct D12 : D1, D2 {
    D12(int x) : B(x), D1(x), D2(x) {}
};struct D12 : D1, D2 {
    D12(int x) : D1(x), D2(x) {}
};struct D : virtual B, D1, D2 {
    D(int x) : B(x), D1(x) {}
};virtual base classes should be default-constructible
struct AmphibiousSchoolBus : SchoolBus, AmphibiousVehiclestruct SchoolBus : SchoolVehicle, Busstruct SchoolVehicle : virtual LandVehiclestruct Bus : WheeledVehiclestruct WheeledVehicle : virtual LandVehiclestruct Vehiclestruct AmphibiousVehicle : virtual LandVehicle, virtual WaterVehiclestruct LandVehicle : virtual Vehiclestruct WaterVehicle : virtual VehicleAmphibiousSchoolBus
SchoolBus
AmphibiousVehicle
SchoolVehicle
Bus
LandVehicle
WaterVehicle
LandVehicle
WheeledVehicle
Vehicle
Vehicle
Vehicle
Vehicle
(Left to right DFS)
RAII
inheritance
virtual
constructor
member initializer list
destructor
default constructor
std::initializer_list
in-class initializer
copy ctor
cpy assign op
move ctor
mv assign op
default members
deleted members
rule of 0
rule of 3/5
smart-ptrs
converting constructor
explicit specifier
is-a relation
has-a relation
public inheritance
protected members
using declaration
final specifier
private & protected inheritance
multiple inheritance
diamond problem
empty base optimization
base method hiding problem (shadowing)
virtual methods
override specifier
dynamic type
RTTI
dynamic_cast
typeid
vtables
by value passing problem (slicing)
pure virtual function
abstract class
misc
friends
nested members
conversion operators
operator overloading
member pointers
unions
std optional
std variant
std any
type ereasure
pimpl
enable shared from this with private inheritance
linkage and static (non-member) functions
Liskov substitution principle
function member ref qualification
constexpr virtual
virtual inheritance
aggregate, pod, literal type
implement class in cpp file