#include <stdio.h>

class A {
    public:
        void a() { printf("A::a()\n");};
        virtual void va() = 0;
        virtual void a(int n) { printf("A::a(int %d)\n", n); };
    private:
        void c() { printf("A::c()\n");};
};

class B : public A {
    public:
        void b() { printf("B::b()\n");};
        virtual void vb() {printf("B::vb()\n"); };
        void a(double d) {printf("B::a(double %f)\n", d); };
        void a(int i) {printf("B::a(int %d)\n", i); };
        virtual void va() {printf("B::va()\n"); };
};

class C : public B {
    public:
        virtual void c() {printf("C::c()\n"); };
        void a(float d) {printf("C::a(float %f)\n", d); };
        virtual void a() {printf("C::a()\n"); };
        virtual void va() {printf("C::va()\n"); };
};

int main() {
    // A a; A abstrakte Klasse
    B b;
    C c;
    A* pa=&b;
    B* pb=&c;
    float x = 1.2;
    pa->a(); // A::a()
    pa->va(); // B::va()
    pa->a(1); // B::a(int)
    // pa->c(); A::c() private, hier nicht sichtbar
    // pa->b(); pa ist vom Typ A* und kennt deswegen b() nicht
    // pa->vb(); pa ist vom Typ A* und kennt deswegen vb() nicht
    pa->a(x); // B::a(int), hier wird double x implizit zu int gecastet
    // pb->a(); pb ist vom Typ B*, hier ist A::a() überladen durch
    // entweder B::a(double) bzw. B::a(int), deswegen existiert B::a() nicht
    pb->va(); // C::va()
    pb->a(1); // B::a(int)
    // pb->c(); A::c() private, deswegen hier nicht sichtbar
    pb->b(); // B::b()
    pb->vb(); // B::vb()
    pb->a(x); // B::a(double)
    pa = &c;
    pa->a(); // A::a()
    pa->va(); // C::va()
    pa->a(1); // B::a(int)
    // pa->c(); A::c() private, hier nicht sichtbar
    // pa->b(); pa ist vom Typ A*, kennt deswegen b() nicht
    // pa->vb(); pa ist vom Typ A*, kennt deswegen vb() nicht
    pa->a(x); // B::a(int), hier wird double x implizit zu int gecastet
}
