With virtual member functions:
#include <iostream>
struct X {
    virtual void f() { std::cout << "X::f()\n"; }
};
struct Y : X {
    // Specifying virtual again here is optional
    // because it can be inferred from X::f().
    virtual void f() { std::cout << "Y::f()\n"; } 
};
void call(X& a) {
    a.f();
}
int main() {
    X x;
    Y y;
    call(x); // outputs "X::f()"
    call(y); // outputs "Y::f()"
}
Without virtual member functions:
#include <iostream>
struct X {
   void f() { std::cout << "X::f()\n"; }
};
struct Y : X {
   void f() { std::cout << "Y::f()\n"; }
};
void call(X& a) {
    a.f();
}
int main() {
    X x;
    Y y;
    call(x); // outputs "X::f()"
    call(y); // outputs "X::f()"
}