Q:

calling to functions with polymorphic pointers

#include <iostream>
class A{};
class AA:public A{};

struct X {
    void f(A *) {
        std::cout << "X::f(A*)\n";
    }
};

struct Y:public X {
    void f(A *) {
        std::cout << "Y::f(A*)\n";
    }
};

int main() {
    Y *y = new Y();
    X *x = new Y();
    const X *cx = new Y();

    y->X::f(new AA);
    x->f(new AA);
}

Print:

X::f(A*) 
X::f(A*)

I don't understand why y->X::f(new AA) and x->f(new AA) wont raise compilation error. I get that X::f(A *) is called in both of the cases. But what is the principle whereby the compiler chooses to use this method? Function overload with polymorphism? Any thumb rules?

A:

Your question implies you expected the behavior you would have gotten if f had been declared virtual in X.  In some languages, that is the only possible behavior.  In C++ you have a choice.  
As you declared f, it uses the compile time type so x-f(new AA) calls X::f  because x is an X*
If you had declared f virtual in X the x-f(new AA) would call Y::f because x points to a Y
For the other aspect of your question (why there is no error involved in calling X::f for a object of type Y), X is a base class of Y, so there should be a valid object of type X buried inside each object of type Y and that X object should be usable with any X method.
Until seeing above comments, I missed the third aspect of your question, that the compiler deduces the need for an implicit cast from AA* to A* when you pass an AA* to a method that needs an A* and A is a base class of AA.  That deduction is largely separate from the compile time or run time choice between X::f and Y::f

