ポインターがスーパータイプの場合

ポインターが指すインスタンスの(実行時の)型よりも、そのポインター変数の型がスーパータイプだった場合、そのポインター変数の型の段階でメソッドに virtual がないと、サブタイプでのメソッドのオーバーライドが無視され、呼ばれない。

#include 
using namespace std;

class T {
public:
    int f(int x) {
        return x + 1;
    }
};

class U : public T {
public:
    virtual int f(int x) {
        return x + 10;
    }
};

class V : public U {
public:
    int f(int x) {
        return x + 100;
    }
};

void main() {
    T* p = new V();
    int y = p->f(0);
    cout << "y == " << y << endl;
    delete p;
}

の実行結果は y == 1 となる。T の段階で virtual が付いていないので、サブタイプの段階でオーバーライドされているかどうかの検索が打ち切られてしまっている。
ちなみに、もし、

    U* p = new V();

ならば実行結果は y == 100 となる。なお V で virtual がなくても上述のように暗黙の内に virtual 扱いになっている。