Virtual và virtual=0?

Về việc kế thừa: Thực chất dù có virtual hay không virtual thì lớp con đều có thể ghi đè lên (override) bất kỳ một hàm nào của lớp cha. Vấn đề chỉ xảy ra khi bạn sử dụng đa hình (polymophism).
Giả sử như sau:

class A{
    public: void display(){printf("a\n");}
}

class B: public A{
    public: void display(){printf("b\n");}
}

void main(){
    A a;
    B b;
    a.display();
    b.display();
    A *p;
    p = new B();
    p -> display();
}

Khi đó kết quả sẽ là

a
b
a

Khi có virtual:

class A{
    public: virtual void display(){printf("a\n");}
}

Kết quả sẽ là:

a
b
b

Còn về việc virtual = 0

class A{
    public: virtual void display()=0;
}

Khi đó, bạn định nghĩa một hàm thuần ảo không có thân hàm (body), không có nội dung xử lý (lưu ý các hàm virtual ở các ví dụ trước đều phải viết nội dung xử lý của hàm). Khi đó, lớp A sẽ là lớp trừu tượng (abstract class) và bạn không được phép tạo đối tượng / thực thể (instance) của lớp A (Chẳng hạn new A() sẽ báo lỗi). Các lớp kế thừa nó, nếu không viết lại (override) hàm display thì sẽ tiếp tục là lớp trừu tượng, cho tới khi có một lớp kế thừa và viết lại hàm display.

Ngoài lề: Một class chỉ có các hàm thuần ảo được gọi là interface. Vấn đề về abstract class, interface dùng để làm gì thì khi học một xíu nữa về thiết kế hướng đối tượng, mẫu thiết kế bạn sẽ thấy rõ ứng dụng của nó hơn.